The branch, v3-5-test has been updated
       via  0047845... Make us pass RAW-CHKPATH with a case sensitive share. I 
know Volker will look at this closely so here's the explaination :-). 
Originally on a case-sensitive share we simply did a stat (or lstat) call and 
returned success of fail based on the result. However this failed to take 
account of incoming paths with a wildcard (which must always fail, and with 
different error messages depending on whether the wildcard is the last 
component or in the path). Also it failed to take account of a stat fail with 
ENOENT due to a missing component of the path as the last component (which is 
ok as it could be a new file)  or if the ENOENT was due to the missing 
component within the path (not the last component) - which must return the 
correct error. What this means is that with "case sensitive = yes" we do one 
more talloc call (to get the parent directory) and one more stat call (on the 
parent directory) in the case where the stat call fails. I think this is an 
acceptabl
 e overhead to enable case sensitive shares to return the correct error 
messages for applications. Volker please examine carefully :-). Jeremy. (cherry 
picked from commit c96d487ae3c65c17b377bb316adac4b5775448f3)
       via  d99584e... Add RAW-CHKPATH test with case-sensitive share. Jeremy. 
(cherry picked from commit 108da2adaf77c152fd292bbdf5645923659a7c2c)
      from  27522fa... s3-registry: fix REG_MULTI_SZ handling in 
registry_push_value.

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-5-test


- Log -----------------------------------------------------------------
commit 00478458b56a0eea52e08605f9f1746abe22109f
Author: Jeremy Allison <[email protected]>
Date:   Wed Nov 25 13:17:56 2009 -0800

    Make us pass RAW-CHKPATH with a case sensitive share.
    I know Volker will look at this closely so here's the explaination :-).
    Originally on a case-sensitive share we simply did a stat (or lstat)
    call and returned success of fail based on the result. However this
    failed to take account of incoming paths with a wildcard (which must
    always fail, and with different error messages depending on whether
    the wildcard is the last component or in the path). Also it failed
    to take account of a stat fail with ENOENT due to a missing component
    of the path as the last component (which is ok as it could be a new
    file)  or if the ENOENT was due to the missing component within
    the path (not the last component) - which must return the correct
    error. What this means is that with "case sensitive = yes" we do
    one more talloc call (to get the parent directory) and one more
    stat call (on the parent directory) in the case where the stat
    call fails. I think this is an acceptable overhead to enable
    case sensitive shares to return the correct error messages for
    applications. Volker please examine carefully :-).
    Jeremy.
    (cherry picked from commit c96d487ae3c65c17b377bb316adac4b5775448f3)

commit d99584e5cd2edd382236f1b083e7274428dfe3ac
Author: Jeremy Allison <[email protected]>
Date:   Wed Nov 25 13:17:38 2009 -0800

    Add RAW-CHKPATH test with case-sensitive share.
    Jeremy.
    (cherry picked from commit 108da2adaf77c152fd292bbdf5645923659a7c2c)

-----------------------------------------------------------------------

Summary of changes:
 source3/script/tests/selftest.sh      |    3 +
 source3/script/tests/test_posix_s3.sh |    4 +
 source3/smbd/filename.c               |  147 +++++++++++++++++++++++---------
 3 files changed, 112 insertions(+), 42 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/script/tests/selftest.sh b/source3/script/tests/selftest.sh
index 80e5042..c952ef2 100755
--- a/source3/script/tests/selftest.sh
+++ b/source3/script/tests/selftest.sh
@@ -266,6 +266,9 @@ cat >$SERVERCONFFILE<<EOF
 [hideunread]
        copy = tmp
        hide unreadable = yes
+[tmpcase]
+       copy = tmp
+       case sensitive = yes
 [hideunwrite]
        copy = tmp
        hide unwriteable files = yes
diff --git a/source3/script/tests/test_posix_s3.sh 
b/source3/script/tests/test_posix_s3.sh
index 11fe247..f2f137b 100755
--- a/source3/script/tests/test_posix_s3.sh
+++ b/source3/script/tests/test_posix_s3.sh
@@ -96,6 +96,10 @@ for t in $tests; do
     else
            testit "$name" $VALGRIND $SMBTORTURE4 $TORTURE4_OPTIONS $ADDARGS 
$unc -U"$username"%"$password" $t || failed=`expr $failed + 1`
     fi
+    if [ "$t" = "RAW-CHKPATH" ]; then
+           echo "Testing with case sensitive"
+           testit "$name" $VALGRIND $SMBTORTURE4 $TORTURE4_OPTIONS $ADDARGS 
"$unc"case -U"$username"%"$password" $t || failed=`expr $failed + 1`
+    fi
 done
 
 testok $0 $failed
diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 16e3631..ab79dfd 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -80,6 +80,24 @@ static NTSTATUS determine_path_error(const char *name,
        }
 }
 
+static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname)
+{
+       /* Ensure we catch all names with in "/."
+          this is disallowed under Windows and
+          in POSIX they've already been removed. */
+       const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
+       if (p) {
+               if (p[2] == '/') {
+                       /* Error code within a pathname. */
+                       return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+               } else if (p[2] == '\0') {
+                       /* Error code at the end of a pathname. */
+                       return NT_STATUS_OBJECT_NAME_INVALID;
+               }
+       }
+       return NT_STATUS_OK;
+}
+
 /****************************************************************************
 This routine is called to convert names from the dos namespace to unix
 namespace. It needs to handle any case conversions, mangling, format changes,
@@ -294,52 +312,103 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
        }
 
        /*
-        * stat the name - if it exists then we can add the stream back (if
-        * there was one) and be done!
+        * If we have a wildcard we must walk the path to
+        * find where the error is, even if case sensitive
+        * is true.
         */
 
-       if (posix_pathnames) {
-               ret = SMB_VFS_LSTAT(conn, smb_fname);
-       } else {
-               ret = SMB_VFS_STAT(conn, smb_fname);
+       name_has_wildcard = ms_has_wild(smb_fname->base_name);
+       if (name_has_wildcard && !allow_wcard_last_component) {
+               /* Wildcard not valid anywhere. */
+               status = NT_STATUS_OBJECT_NAME_INVALID;
+               goto fail;
        }
 
-       if (ret == 0) {
-               /* Ensure we catch all names with in "/."
-                  this is disallowed under Windows. */
-               const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/
-               if (p) {
-                       if (p[2] == '/') {
-                               /* Error code within a pathname. */
-                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
-                               goto fail;
-                       } else if (p[2] == '\0') {
-                               /* Error code at the end of a pathname. */
-                               status = NT_STATUS_OBJECT_NAME_INVALID;
+       DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
+                smb_fname->base_name, dirpath, start));
+
+       if (!name_has_wildcard) {
+               /*
+                * stat the name - if it exists then we can add the stream back 
(if
+                * there was one) and be done!
+                */
+
+               if (posix_pathnames) {
+                       ret = SMB_VFS_LSTAT(conn, smb_fname);
+               } else {
+                       ret = SMB_VFS_STAT(conn, smb_fname);
+               }
+
+               if (ret == 0) {
+                       status = check_for_dot_component(smb_fname);
+                       if (!NT_STATUS_IS_OK(status)) {
                                goto fail;
                        }
+                       /* Add the path (not including the stream) to the 
cache. */
+                       stat_cache_add(orig_path, smb_fname->base_name,
+                                      conn->case_sensitive);
+                       DEBUG(5,("conversion of base_name finished %s -> %s\n",
+                                orig_path, smb_fname->base_name));
+                       goto done;
                }
-               /* Add the path (not including the stream) to the cache. */
-               stat_cache_add(orig_path, smb_fname->base_name,
-                              conn->case_sensitive);
-               DEBUG(5,("conversion of base_name finished %s -> %s\n",
-                        orig_path, smb_fname->base_name));
-               goto done;
-       }
 
-       DEBUG(5,("unix_convert begin: name = %s, dirpath = %s, start = %s\n",
-                smb_fname->base_name, dirpath, start));
+               /*
+                * A special case - if we don't have any wildcards or mangling 
chars and are case
+                * sensitive or the underlying filesystem is case insentive 
then searching
+                * won't help.
+                */
 
-       /*
-        * A special case - if we don't have any mangling chars and are case
-        * sensitive or the underlying filesystem is case insentive then 
searching
-        * won't help.
-        */
+               if ((conn->case_sensitive || !(conn->fs_capabilities &
+                                       FILE_CASE_SENSITIVE_SEARCH)) &&
+                               !mangle_is_mangled(smb_fname->base_name, 
conn->params)) {
 
-       if ((conn->case_sensitive || !(conn->fs_capabilities &
-                                      FILE_CASE_SENSITIVE_SEARCH)) &&
-           !mangle_is_mangled(smb_fname->base_name, conn->params)) {
-               goto done;
+                       status = check_for_dot_component(smb_fname);
+                       if (!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+
+                       /*
+                        * The stat failed. Could be ok as it could be
+                        * a new file.
+                        */
+
+                       if (errno == ENOTDIR || errno == ELOOP) {
+                               status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                               goto fail;
+                       } else if (errno == ENOENT) {
+                               /*
+                                * Was it a missing last component ?
+                                * or a missing intermediate component ?
+                                */
+                               struct smb_filename parent_fname;
+                               ZERO_STRUCT(parent_fname);
+                               if (!parent_dirname(ctx, smb_fname->base_name,
+                                                       &parent_fname.base_name,
+                                                       NULL)) {
+                                       status = NT_STATUS_NO_MEMORY;
+                                       goto fail;
+                               }
+                               if (posix_pathnames) {
+                                       ret = SMB_VFS_LSTAT(conn, 
&parent_fname);
+                               } else {
+                                       ret = SMB_VFS_STAT(conn, &parent_fname);
+                               }
+                               if (ret == -1) {
+                                       if (errno == ENOTDIR ||
+                                                       errno == ENOENT ||
+                                                       errno == ELOOP) {
+                                               status = 
NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                                               goto fail;
+                                       }
+                               }
+                               /*
+                                * Missing last component is ok - new file.
+                                * Also deal with permission denied elsewhere.
+                                * Just drop out to done.
+                                */
+                               goto done;
+                       }
+               }
        }
 
        /*
@@ -404,12 +473,6 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx,
 
                name_has_wildcard = ms_has_wild(start);
 
-               /* Wildcard not valid anywhere. */
-               if (name_has_wildcard && !allow_wcard_last_component) {
-                       status = NT_STATUS_OBJECT_NAME_INVALID;
-                       goto fail;
-               }
-
                /* Wildcards never valid within a pathname. */
                if (name_has_wildcard && end) {
                        status = NT_STATUS_OBJECT_NAME_INVALID;


-- 
Samba Shared Repository

Reply via email to