s3: libsmbclient: Work around bugs in SLES cifsd and Apple smbx SMB1 servers.
authorJeremy Allison <jra@samba.org>
Fri, 9 May 2014 04:31:49 +0000 (21:31 -0700)
committerStefan Metzmacher <metze@samba.org>
Fri, 9 May 2014 21:10:07 +0000 (23:10 +0200)
SLES's cifsd and Apple's smbx do not correctly handle FILE_NON_DIRECTORY_FILE
which prevents recursive copies in gvfs from working correctly [1] since GVFS
tries to open the directory, expecting ENOTDIR, but it suceeds and appears as a
zero byte file.

This fix adds code to the cli_open() open code that checks if
CreateOptions was requested with FILE_NON_DIRECTORY_FILE set,
and if the attributes returned include FILE_ATTRIBUTE_DIRECTORY
we synchronously close the file handle just opened, and return
NT_STATUS_FILE_IS_A_DIRECTORY to the caller.

Depends on the previous API update to cli_ntcreate()
to add returned attributes.

Fixes bug #10587 - Opening directories on SLES's cifsd and Apple's smbx succeeds.

https://bugzilla.samba.org/show_bug.cgi?id=10587

Signed-off-by: Jeremy Allison <jra@samba.org>
Reviewed-by: Stefan Metzmacher <metze@samba.org>
source3/libsmb/clifile.c

index 7f562a8061a2d462ef605632fc2306c523efcd10..70b769d1bd84d7c2eb0f104d86a8f797819db4c3 100644 (file)
@@ -2387,6 +2387,7 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
        unsigned int openfn = 0;
        unsigned int dos_deny = 0;
        uint32_t access_mask, share_mode, create_disposition, create_options;
+       struct smb_create_returns cr;
 
        /* Do the initial mapping into OpenX parameters. */
        if (flags & O_CREAT) {
@@ -2468,7 +2469,7 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                                create_options,
                                0,
                                pfnum,
-                               NULL);
+                               &cr);
 
        /* Try and cope will all varients of "we don't do this call"
           and fall back to openX. */
@@ -2485,6 +2486,25 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
                goto try_openx;
        }
 
+       if (NT_STATUS_IS_OK(status) &&
+           (create_options & FILE_NON_DIRECTORY_FILE) &&
+           (cr.file_attributes & FILE_ATTRIBUTE_DIRECTORY))
+       {
+               /*
+                * Some (broken) servers return a valid handle
+                * for directories even if FILE_NON_DIRECTORY_FILE
+                * is set. Just close the handle and set the
+                * error explicitly to NT_STATUS_FILE_IS_A_DIRECTORY.
+                */
+               status = cli_close(cli, *pfnum);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+               /* Set this so libsmbclient can retrieve it. */
+               cli->raw_status = status;
+       }
+
        return status;
 
   try_openx: