s3:smbd: only pass UCF_PREP_CREATEFILE to filename_convert() if we may create a new...
authorStefan Metzmacher <metze@samba.org>
Thu, 13 Oct 2016 10:42:59 +0000 (12:42 +0200)
committerKarolin Seeger <kseeger@samba.org>
Mon, 2 Jan 2017 10:56:50 +0000 (11:56 +0100)
This fixes a regression introduced by commit
f98d10af2a05f0261611f4cabdfe274cd9fe91c0
(smbd: Always use UCF_PREP_CREATEFILE for filename_convert calls to resolve a path for open)

The main problem was that Windows client seem to verify
the access to user.V2\ntuser.ini is rejected with NT_STATUS_ACCESS_DENIED,
using the machine credentials.

Passing UCF_PREP_CREATEFILE to filename_convert() triggers a code path
that implements a dropbox behaviour. A dropbox is a directory with only -wx permissions,
so get_real_filename fails with EACCESS, it needs to list the directory.
EACCESS is ignored with UCF_PREP_CREATEFILE.

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

Signed-off-by: Stefan Metzmacher <metze@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
Autobuild-User(master): Jeremy Allison <jra@samba.org>
Autobuild-Date(master): Tue Oct 25 05:33:36 CEST 2016 on sn-devel-144

(cherry picked from commit 759416582c54a16aacbef0e0dfe4649bddff8c5e)

source3/smbd/filename.c
source3/smbd/nttrans.c
source3/smbd/proto.h
source3/smbd/reply.c
source3/smbd/smb2_create.c

index e89575d52eaf71bb98cbef486191113298f5ef1a..ce40c0a502fbd914042d5bdf7326b725a2528555 100644 (file)
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 
+uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition)
+{
+       uint32_t ucf_flags = 0;
+
+       if (req != NULL && req->posix_pathnames) {
+               ucf_flags |= UCF_POSIX_PATHNAMES;
+       }
+
+       switch (create_disposition) {
+       case FILE_OPEN:
+       case FILE_OVERWRITE:
+               break;
+       case FILE_SUPERSEDE:
+       case FILE_CREATE:
+       case FILE_OPEN_IF:
+       case FILE_OVERWRITE_IF:
+               ucf_flags |= UCF_PREP_CREATEFILE;
+               break;
+       }
+
+       return ucf_flags;
+}
+
 static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx,
                                  connection_struct *conn,
                                  struct smb_filename *smb_fname);
index 32c54e7dda904be505910444230c5ce40afd433b..ad169d99529887f897744b53323af2477560addc 100644 (file)
@@ -461,8 +461,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
        int oplock_request;
        uint8_t oplock_granted = NO_OPLOCK_RETURN;
        struct case_semantics_state *case_state = NULL;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBntcreateX);
@@ -536,6 +535,7 @@ void reply_ntcreate_and_X(struct smb_request *req)
                }
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
        status = filename_convert(ctx,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
@@ -1024,8 +1024,7 @@ static void call_nt_transact_create(connection_struct *conn,
        int oplock_request;
        uint8_t oplock_granted;
        struct case_semantics_state *case_state = NULL;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        DEBUG(5,("call_nt_transact_create\n"));
@@ -1106,6 +1105,7 @@ static void call_nt_transact_create(connection_struct *conn,
                }
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
        status = filename_convert(ctx,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
index dcfd829d2376c0c8770e741d0b9f6cb79409621e..ca8ea575b33eda22e4ea83415bae50868affdaca 100644 (file)
@@ -325,6 +325,7 @@ int fsp_stat(files_struct *fsp);
 
 /* The following definitions come from smbd/filename.c  */
 
+uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition);
 NTSTATUS unix_convert(TALLOC_CTX *ctx,
                      connection_struct *conn,
                      const char *orig_path,
index 72fa5a42c856dacb076e6924c6b9a4e784d49a1d..6b16458e19cad3df3b964bd4c5c88d07fbf5110d 100644 (file)
@@ -2097,8 +2097,7 @@ void reply_open(struct smb_request *req)
        uint32_t create_options = 0;
        uint32_t private_flags = 0;
        NTSTATUS status;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBopen);
@@ -2127,6 +2126,8 @@ void reply_open(struct smb_request *req)
                goto out;
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
+
        status = filename_convert(ctx,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
@@ -2251,8 +2252,7 @@ void reply_open_and_X(struct smb_request *req)
        uint32_t create_disposition;
        uint32_t create_options = 0;
        uint32_t private_flags = 0;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBopenX);
@@ -2299,6 +2299,8 @@ void reply_open_and_X(struct smb_request *req)
                goto out;
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
+
        status = filename_convert(ctx,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
@@ -2511,8 +2513,7 @@ void reply_mknew(struct smb_request *req)
        uint32_t share_mode = FILE_SHARE_READ|FILE_SHARE_WRITE;
        uint32_t create_disposition;
        uint32_t create_options = 0;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBcreate);
@@ -2526,6 +2527,14 @@ void reply_mknew(struct smb_request *req)
        fattr = SVAL(req->vwv+0, 0);
        oplock_request = CORE_OPLOCK_REQUEST(req->inbuf);
 
+       if (req->cmd == SMBmknew) {
+               /* We should fail if file exists. */
+               create_disposition = FILE_CREATE;
+       } else {
+               /* Create if file doesn't exist, truncate if it does. */
+               create_disposition = FILE_OVERWRITE_IF;
+       }
+
        /* mtime. */
        ft.mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+1));
 
@@ -2536,6 +2545,7 @@ void reply_mknew(struct smb_request *req)
                goto out;
        }
 
+       ucf_flags = filename_create_ucf_flags(req, create_disposition);
        status = filename_convert(ctx,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
@@ -2560,14 +2570,6 @@ void reply_mknew(struct smb_request *req)
                         smb_fname_str_dbg(smb_fname)));
        }
 
-       if(req->cmd == SMBmknew) {
-               /* We should fail if file exists. */
-               create_disposition = FILE_CREATE;
-       } else {
-               /* Create if file doesn't exist, truncate if it does. */
-               create_disposition = FILE_OVERWRITE_IF;
-       }
-
        status = SMB_VFS_CREATE_FILE(
                conn,                                   /* conn */
                req,                                    /* req */
@@ -2644,8 +2646,7 @@ void reply_ctemp(struct smb_request *req)
        char *s;
        NTSTATUS status;
        int i;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBctemp);
@@ -2682,6 +2683,7 @@ void reply_ctemp(struct smb_request *req)
                        goto out;
                }
 
+               ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
                status = filename_convert(ctx, conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
@@ -6107,8 +6109,7 @@ void reply_mkdir(struct smb_request *req)
        struct smb_filename *smb_dname = NULL;
        char *directory = NULL;
        NTSTATUS status;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (req->posix_pathnames ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBmkdir);
@@ -6120,6 +6121,7 @@ void reply_mkdir(struct smb_request *req)
                goto out;
        }
 
+       ucf_flags = filename_create_ucf_flags(req, FILE_CREATE);
        status = filename_convert(ctx, conn,
                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                 directory,
index 17bddc1266a9b0403273fd3537d26e675a2d0e3a..46eb8396479988b44f337cf124acbac7da78ae80 100644 (file)
@@ -374,12 +374,12 @@ static bool smb2_lease_key_valid(const struct smb2_lease_key *key)
        return ((key->data[0] != 0) || (key->data[1] != 0));
 }
 
-static NTSTATUS smbd_smb2_create_durable_lease_check(
+static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req,
        const char *requested_filename, const struct files_struct *fsp,
        const struct smb2_lease *lease_ptr)
 {
        struct smb_filename *smb_fname = NULL;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE;
+       uint32_t ucf_flags;
        NTSTATUS status;
 
        if (lease_ptr == NULL) {
@@ -404,6 +404,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
+       ucf_flags = filename_create_ucf_flags(smb1req, FILE_OPEN);
        status = filename_convert(talloc_tos(), fsp->conn, false,
                                  requested_filename, ucf_flags,
                                  NULL, &smb_fname);
@@ -1051,7 +1052,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                   (unsigned)result->oplock_type, lease_ptr));
 
                        status = smbd_smb2_create_durable_lease_check(
-                               fname, result, lease_ptr);
+                               smb1req, fname, result, lease_ptr);
                        if (!NT_STATUS_IS_OK(status)) {
                                close_file(smb1req, result, SHUTDOWN_CLOSE);
                                tevent_req_nterror(req, status);
@@ -1072,7 +1073,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                        info = FILE_WAS_OPENED;
                } else {
                        struct smb_filename *smb_fname = NULL;
-                       uint32_t ucf_flags = UCF_PREP_CREATEFILE;
+                       uint32_t ucf_flags;
 
                        if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
                                if (lease_ptr == NULL) {
@@ -1096,6 +1097,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
                                }
                        }
 
+                       ucf_flags = filename_create_ucf_flags(smb1req, in_create_disposition);
                        status = filename_convert(req,
                                                  smb1req->conn,
                                                  smb1req->flags2 & FLAGS2_DFS_PATHNAMES,