Fix spelling mistakes
[bbaumbach/samba-autobuild/.git] / source3 / smbd / reply.c
index b1ca7a54ff7ed9e571440fdd971931b31db406d0..f2617fab3b3719ceb748d1d870e329a09cdd149d 100644 (file)
@@ -25,6 +25,7 @@
 */
 
 #include "includes.h"
+#include "libsmb/namequery.h"
 #include "system/filesys.h"
 #include "printing.h"
 #include "smbd/smbd.h"
@@ -32,7 +33,6 @@
 #include "fake_file.h"
 #include "rpc_client/rpc_client.h"
 #include "../librpc/gen_ndr/ndr_spoolss_c.h"
-#include "../librpc/gen_ndr/open_files.h"
 #include "rpc_client/cli_spoolss.h"
 #include "rpc_client/init_spoolss.h"
 #include "rpc_server/rpc_ncacn_np.h"
@@ -190,16 +190,16 @@ static NTSTATUS check_path_syntax_internal(char *path,
                        switch(siz) {
                                case 5:
                                        *d++ = *s++;
-                                       /*fall through*/
+                                       FALL_THROUGH;
                                case 4:
                                        *d++ = *s++;
-                                       /*fall through*/
+                                       FALL_THROUGH;
                                case 3:
                                        *d++ = *s++;
-                                       /*fall through*/
+                                       FALL_THROUGH;
                                case 2:
                                        *d++ = *s++;
-                                       /*fall through*/
+                                       FALL_THROUGH;
                                case 1:
                                        *d++ = *s++;
                                        break;
@@ -253,15 +253,17 @@ NTSTATUS check_path_syntax_posix(char *path)
 
 /****************************************************************************
  Pull a string and check the path allowing a wilcard - provide for error return.
+ Passes in posix flag.
 ****************************************************************************/
 
-size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
+static size_t srvstr_get_path_wcard_internal(TALLOC_CTX *ctx,
                        const char *base_ptr,
                        uint16_t smb_flags2,
                        char **pp_dest,
                        const char *src,
                        size_t src_len,
                        int flags,
+                       bool posix_pathnames,
                        NTSTATUS *err,
                        bool *contains_wcard)
 {
@@ -288,7 +290,7 @@ size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
                return ret;
        }
 
-       if (lp_posix_pathnames()) {
+       if (posix_pathnames) {
                *err = check_path_syntax_posix(*pp_dest);
        } else {
                *err = check_path_syntax_wcard(*pp_dest, contains_wcard);
@@ -297,6 +299,59 @@ size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
        return ret;
 }
 
+/****************************************************************************
+ Pull a string and check the path allowing a wilcard - provide for error return.
+****************************************************************************/
+
+size_t srvstr_get_path_wcard(TALLOC_CTX *ctx,
+                       const char *base_ptr,
+                       uint16_t smb_flags2,
+                       char **pp_dest,
+                       const char *src,
+                       size_t src_len,
+                       int flags,
+                       NTSTATUS *err,
+                       bool *contains_wcard)
+{
+       return srvstr_get_path_wcard_internal(ctx,
+                       base_ptr,
+                       smb_flags2,
+                       pp_dest,
+                       src,
+                       src_len,
+                       flags,
+                       false,
+                       err,
+                       contains_wcard);
+}
+
+/****************************************************************************
+ Pull a string and check the path allowing a wilcard - provide for error return.
+ posix_pathnames version.
+****************************************************************************/
+
+size_t srvstr_get_path_wcard_posix(TALLOC_CTX *ctx,
+                       const char *base_ptr,
+                       uint16_t smb_flags2,
+                       char **pp_dest,
+                       const char *src,
+                       size_t src_len,
+                       int flags,
+                       NTSTATUS *err,
+                       bool *contains_wcard)
+{
+       return srvstr_get_path_wcard_internal(ctx,
+                       base_ptr,
+                       smb_flags2,
+                       pp_dest,
+                       src,
+                       src_len,
+                       flags,
+                       true,
+                       err,
+                       contains_wcard);
+}
+
 /****************************************************************************
  Pull a string and check the path - provide for error return.
 ****************************************************************************/
@@ -311,10 +366,46 @@ size_t srvstr_get_path(TALLOC_CTX *ctx,
                        NTSTATUS *err)
 {
        bool ignore;
-       return srvstr_get_path_wcard(ctx, base_ptr, smb_flags2, pp_dest, src,
-                                    src_len, flags, err, &ignore);
+       return srvstr_get_path_wcard_internal(ctx,
+                       base_ptr,
+                       smb_flags2,
+                       pp_dest,
+                       src,
+                       src_len,
+                       flags,
+                       false,
+                       err,
+                       &ignore);
+}
+
+/****************************************************************************
+ Pull a string and check the path - provide for error return.
+ posix_pathnames version.
+****************************************************************************/
+
+size_t srvstr_get_path_posix(TALLOC_CTX *ctx,
+                       const char *base_ptr,
+                       uint16_t smb_flags2,
+                       char **pp_dest,
+                       const char *src,
+                       size_t src_len,
+                       int flags,
+                       NTSTATUS *err)
+{
+       bool ignore;
+       return srvstr_get_path_wcard_internal(ctx,
+                       base_ptr,
+                       smb_flags2,
+                       pp_dest,
+                       src,
+                       src_len,
+                       flags,
+                       true,
+                       err,
+                       &ignore);
 }
 
+
 size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
                                 char **pp_dest, const char *src, int flags,
                                 NTSTATUS *err, bool *contains_wcard)
@@ -326,9 +417,29 @@ size_t srvstr_get_path_req_wcard(TALLOC_CTX *mem_ctx, struct smb_request *req,
                return 0;
        }
 
-       return srvstr_get_path_wcard(mem_ctx, (const char *)req->inbuf,
-                                    req->flags2, pp_dest, src, bufrem, flags,
-                                    err, contains_wcard);
+       if (req->posix_pathnames) {
+               return srvstr_get_path_wcard_internal(mem_ctx,
+                               (const char *)req->inbuf,
+                               req->flags2,
+                               pp_dest,
+                               src,
+                               bufrem,
+                               flags,
+                               true,
+                               err,
+                               contains_wcard);
+       } else {
+               return srvstr_get_path_wcard_internal(mem_ctx,
+                               (const char *)req->inbuf,
+                               req->flags2,
+                               pp_dest,
+                               src,
+                               bufrem,
+                               flags,
+                               false,
+                               err,
+                               contains_wcard);
+       }
 }
 
 size_t srvstr_get_path_req(TALLOC_CTX *mem_ctx, struct smb_request *req,
@@ -668,7 +779,9 @@ void reply_special(struct smbXsrv_connection *xconn, char *inbuf, size_t inbuf_s
        DEBUG(5,("init msg_type=0x%x msg_flags=0x%x\n",
                    msg_type, msg_flags));
 
-       srv_send_smb(xconn, outbuf, false, 0, false, NULL);
+       if (!srv_send_smb(xconn, outbuf, false, 0, false, NULL)) {
+               exit_server_cleanly("reply_special: srv_send_smb failed.");
+       }
 
        if (CVAL(outbuf, 0) != 0x82) {
                exit_server_cleanly("invalid netbios session");
@@ -756,7 +869,7 @@ void reply_tcon_and_X(struct smb_request *req)
        connection_struct *conn = req->conn;
        const char *service = NULL;
        TALLOC_CTX *ctx = talloc_tos();
-       /* what the cleint thinks the device is */
+       /* what the client thinks the device is */
        char *client_devicetype = NULL;
        /* what the server tells the client the share represents */
        const char *server_devicetype;
@@ -810,6 +923,11 @@ void reply_tcon_and_X(struct smb_request *req)
                }
 
                TALLOC_FREE(tcon);
+               /*
+                * This tree id is gone. Make sure we can't re-use it
+                * by accident.
+                */
+               req->tid = 0;
        }
 
        if ((passlen > MAX_PASS_LEN) || (passlen >= req->buflen)) {
@@ -1165,7 +1283,7 @@ void reply_checkpath(struct smb_request *req)
        struct smb_filename *smb_fname = NULL;
        char *name = NULL;
        NTSTATUS status;
-       uint32_t ucf_flags = (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBcheckpath);
@@ -1184,10 +1302,10 @@ void reply_checkpath(struct smb_request *req)
 
        status = filename_convert(ctx,
                                conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
                                name,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -1280,14 +1398,13 @@ void reply_getatr(struct smb_request *req)
                size = 0;
                mtime = 0;
        } else {
-               uint32_t ucf_flags = (lp_posix_pathnames() ?
-                               UCF_POSIX_PATHNAMES : 0);
+               uint32_t ucf_flags = ucf_flags_from_smb_request(req);
                status = filename_convert(ctx,
                                conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -1367,7 +1484,7 @@ void reply_setatr(struct smb_request *req)
        time_t mtime;
        const char *p;
        NTSTATUS status;
-       uint32_t ucf_flags = (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBsetatr);
@@ -1388,10 +1505,10 @@ void reply_setatr(struct smb_request *req)
 
        status = filename_convert(ctx,
                                conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
                                fname,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -1462,9 +1579,20 @@ void reply_dskattr(struct smb_request *req)
        connection_struct *conn = req->conn;
        uint64_t ret;
        uint64_t dfree,dsize,bsize;
+       struct smb_filename smb_fname;
        START_PROFILE(SMBdskattr);
 
-       ret = get_dfree_info(conn, ".", &bsize, &dfree, &dsize);
+       ZERO_STRUCT(smb_fname);
+       smb_fname.base_name = discard_const_p(char, ".");
+
+       if (SMB_VFS_STAT(conn, &smb_fname) != 0) {
+               reply_nterror(req, map_nt_error_from_unix(errno));
+               DBG_WARNING("stat of . failed (%s)\n", strerror(errno));
+               END_PROFILE(SMBdskattr);
+               return;
+       }
+
+       ret = get_dfree_info(conn, &smb_fname, &bsize, &dfree, &dsize);
        if (ret == (uint64_t)-1) {
                reply_nterror(req, map_nt_error_from_unix(errno));
                END_PROFILE(SMBdskattr);
@@ -1644,7 +1772,7 @@ void reply_search(struct smb_request *req)
                goto out;
        }
 
-       if (lp_posix_pathnames()) {
+       if (req->posix_pathnames) {
                reply_unknown_new(req, req->cmd);
                goto out;
        }
@@ -1672,12 +1800,13 @@ void reply_search(struct smb_request *req)
        /* dirtype &= ~FILE_ATTRIBUTE_DIRECTORY; */
 
        if (status_len == 0) {
+               struct smb_filename *smb_dname = NULL;
                uint32_t ucf_flags = UCF_ALWAYS_ALLOW_WCARD_LCOMP |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+                       ucf_flags_from_smb_request(req);
                nt_status = filename_convert(ctx, conn,
-                                            req->flags2 & FLAGS2_DFS_PATHNAMES,
                                             path,
                                             ucf_flags,
+                                            NULL,
                                             &mask_contains_wcard,
                                             &smb_fname);
                if (!NT_STATUS_IS_OK(nt_status)) {
@@ -1710,10 +1839,20 @@ void reply_search(struct smb_request *req)
                memset((char *)status,'\0',21);
                SCVAL(status,0,(dirtype & 0x1F));
 
+               smb_dname = synthetic_smb_fname(talloc_tos(),
+                                       directory,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+               if (smb_dname == NULL) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
+                       goto out;
+               }
+
                nt_status = dptr_create(conn,
                                        NULL, /* req */
                                        NULL, /* fsp */
-                                       directory,
+                                       smb_dname,
                                        True,
                                        expect_close,
                                        req->smbpid,
@@ -1721,6 +1860,9 @@ void reply_search(struct smb_request *req)
                                        mask_contains_wcard,
                                        dirtype,
                                        &dirptr);
+
+               TALLOC_FREE(smb_dname);
+
                if (!NT_STATUS_IS_OK(nt_status)) {
                        reply_nterror(req, nt_status);
                        goto out;
@@ -1755,7 +1897,7 @@ void reply_search(struct smb_request *req)
                 * For a 'continue' search we have no string. So
                 * check from the initial saved string.
                 */
-               if (!lp_posix_pathnames()) {
+               if (!req->posix_pathnames) {
                        mask_contains_wcard = ms_has_wild(mask);
                }
                dirtype = dptr_attr(sconn, dptr_num);
@@ -1763,9 +1905,6 @@ void reply_search(struct smb_request *req)
 
        DEBUG(4,("dptr_num is %d\n",dptr_num));
 
-       /* Initialize per SMBsearch/SMBffirst/SMBfunique operation data */
-       dptr_init_search_op(dirptr);
-
        if ((dirtype&0x1F) == FILE_ATTRIBUTE_VOLUME) {
                char buf[DIR_STRUCT_SIZE];
                memcpy(buf,status,21);
@@ -1912,7 +2051,7 @@ void reply_fclose(struct smb_request *req)
 
        START_PROFILE(SMBfclose);
 
-       if (lp_posix_pathnames()) {
+       if (req->posix_pathnames) {
                reply_unknown_new(req, req->cmd);
                END_PROFILE(SMBfclose);
                return;
@@ -1975,8 +2114,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 |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBopen);
@@ -2005,12 +2143,14 @@ 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,
                                fname,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2129,8 +2269,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 |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBopenX);
@@ -2177,12 +2316,14 @@ 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,
                                fname,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2389,8 +2530,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 |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBcreate);
@@ -2404,6 +2544,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));
 
@@ -2414,12 +2562,13 @@ 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,
                                fname,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2438,14 +2587,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 */
@@ -2522,8 +2663,7 @@ void reply_ctemp(struct smb_request *req)
        char *s;
        NTSTATUS status;
        int i;
-       uint32_t ucf_flags = UCF_PREP_CREATEFILE |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBctemp);
@@ -2560,11 +2700,12 @@ 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,
                                ucf_flags,
                                NULL,
+                               NULL,
                                &smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -2729,7 +2870,7 @@ static NTSTATUS do_unlink(connection_struct *conn,
        uint32_t dirtype_orig = dirtype;
        NTSTATUS status;
        int ret;
-       bool posix_paths = lp_posix_pathnames();
+       bool posix_paths = (req != NULL && req->posix_pathnames);
 
        DEBUG(10,("do_unlink: %s, dirtype = %d\n",
                  smb_fname_str_dbg(smb_fname),
@@ -2866,6 +3007,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
        char *fname_mask = NULL;
        int count=0;
        NTSTATUS status = NT_STATUS_OK;
+       struct smb_filename *smb_fname_dir = NULL;
        TALLOC_CTX *ctx = talloc_tos();
 
        /* Split up the directory from the filename/mask. */
@@ -2921,7 +3063,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                        dirtype = FILE_ATTRIBUTE_NORMAL;
                }
 
-               status = check_name(conn, smb_fname->base_name);
+               status = check_name(conn, smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        goto out;
                }
@@ -2955,12 +3097,22 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                        }
                }
 
-               status = check_name(conn, fname_dir);
+               smb_fname_dir = synthetic_smb_fname(talloc_tos(),
+                                       fname_dir,
+                                       NULL,
+                                       NULL,
+                                       smb_fname->flags);
+               if (smb_fname_dir == NULL) {
+                       status = NT_STATUS_NO_MEMORY;
+                       goto out;
+               }
+
+               status = check_name(conn, smb_fname_dir);
                if (!NT_STATUS_IS_OK(status)) {
                        goto out;
                }
 
-               dir_hnd = OpenDir(talloc_tos(), conn, fname_dir, fname_mask,
+               dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_dir, fname_mask,
                                  dirtype);
                if (dir_hnd == NULL) {
                        status = map_nt_error_from_unix(errno);
@@ -3019,7 +3171,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
                                goto out;
                        }
 
-                       status = check_name(conn, smb_fname->base_name);
+                       status = check_name(conn, smb_fname);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                TALLOC_FREE(frame);
@@ -3050,6 +3202,7 @@ NTSTATUS unlink_internals(connection_struct *conn, struct smb_request *req,
        }
 
  out:
+       TALLOC_FREE(smb_fname_dir);
        TALLOC_FREE(fname_dir);
        TALLOC_FREE(fname_mask);
        return status;
@@ -3068,7 +3221,7 @@ void reply_unlink(struct smb_request *req)
        NTSTATUS status;
        bool path_contains_wcard = False;
        uint32_t ucf_flags = UCF_COND_ALLOW_WCARD_LCOMP |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+                       ucf_flags_from_smb_request(req);
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBunlink);
@@ -3089,9 +3242,9 @@ void reply_unlink(struct smb_request *req)
        }
 
        status = filename_convert(ctx, conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  name,
                                  ucf_flags,
+                                 NULL,
                                  &path_contains_wcard,
                                  &smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -3537,7 +3690,7 @@ void reply_readbraw(struct smb_request *req)
            (uint64_t)startpos, (uint64_t)maxcount, READ_LOCK,
            &lock);
 
-       if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+       if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                reply_readbraw_error(xconn);
                END_PROFILE(SMBreadbraw);
                return;
@@ -3569,8 +3722,6 @@ void reply_readbraw(struct smb_request *req)
 
        DEBUG(5,("reply_readbraw finished\n"));
 
-       SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-
        END_PROFILE(SMBreadbraw);
        return;
 }
@@ -3750,7 +3901,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
            (uint64_t)startpos, (uint64_t)numtoread, READ_LOCK,
            &lock);
 
-       if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+       if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                END_PROFILE(SMBread);
                return;
@@ -3761,7 +3912,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
 
        if (nread < 0) {
                reply_nterror(req, map_nt_error_from_unix(errno));
-               goto strict_unlock;
+               goto out;
        }
 
        srv_set_message((char *)req->outbuf, 5, nread+3, False);
@@ -3774,9 +3925,7 @@ Returning short read of maximum allowed for compatibility with Windows 2000.\n",
        DEBUG(3, ("read %s num=%d nread=%d\n",
                  fsp_fnum_dbg(fsp), (int)numtoread, (int)nread));
 
-strict_unlock:
-       SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-
+out:
        END_PROFILE(SMBread);
        return;
 }
@@ -3785,10 +3934,9 @@ strict_unlock:
  Setup readX header.
 ****************************************************************************/
 
-static int setup_readX_header(struct smb_request *req, char *outbuf,
-                             size_t smb_maxcnt)
+size_t setup_readX_header(char *outbuf, size_t smb_maxcnt)
 {
-       int outsize;
+       size_t outsize;
 
        outsize = srv_set_message(outbuf,12,smb_maxcnt + 1 /* padding byte */,
                                  False);
@@ -3805,7 +3953,6 @@ static int setup_readX_header(struct smb_request *req, char *outbuf,
              + 2               /* the buflen field */
              + 1);             /* padding byte */
        SSVAL(outbuf,smb_vwv7,(smb_maxcnt >> 16));
-       SSVAL(outbuf,smb_vwv11,smb_maxcnt);
        SCVAL(smb_buf(outbuf), 0, 0); /* padding byte */
        /* Reset the outgoing length, set_message truncates at 0x1FFFF. */
        _smb_setlen_large(outbuf,
@@ -3830,7 +3977,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
            (uint64_t)startpos, (uint64_t)smb_maxcnt, READ_LOCK,
            &lock);
 
-       if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+       if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                return;
        }
@@ -3851,7 +3998,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
 
                if(fsp_stat(fsp) == -1) {
                        reply_nterror(req, map_nt_error_from_unix(errno));
-                       goto strict_unlock;
+                       goto out;
                }
 
                if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
@@ -3873,7 +4020,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
                header = data_blob_const(headerbuf, sizeof(headerbuf));
 
                construct_reply_common_req(req, (char *)headerbuf);
-               setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
+               setup_readX_header((char *)headerbuf, smb_maxcnt);
 
                nread = SMB_VFS_SENDFILE(xconn->transport.sock, fsp, &header,
                                         startpos, smb_maxcnt);
@@ -3913,7 +4060,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
                                DEBUG(3, ("send_file_readX: fake_sendfile %s max=%d nread=%d\n",
                                          fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
                                /* No outbuf here means successful sendfile. */
-                               goto strict_unlock;
+                               goto out;
                        }
 
                        DEBUG(0,("send_file_readX: sendfile failed for file "
@@ -3954,7 +4101,7 @@ static void send_file_readX(connection_struct *conn, struct smb_request *req,
                /* No outbuf here means successful sendfile. */
                SMB_PERFCOUNT_SET_MSGLEN_OUT(&req->pcd, nread);
                SMB_PERFCOUNT_END(&req->pcd);
-               goto strict_unlock;
+               goto out;
        }
 
 normal_read:
@@ -3963,8 +4110,18 @@ normal_read:
                uint8_t headerbuf[smb_size + 2*12 + 1 /* padding byte */];
                ssize_t ret;
 
+               if (!S_ISREG(fsp->fsp_name->st.st_ex_mode) ||
+                   (startpos > fsp->fsp_name->st.st_ex_size) ||
+                   (smb_maxcnt > (fsp->fsp_name->st.st_ex_size - startpos))) {
+                       /*
+                        * We already know that we would do a short
+                        * read, so don't try the sendfile() path.
+                        */
+                       goto nosendfile_read;
+               }
+
                construct_reply_common_req(req, (char *)headerbuf);
-               setup_readX_header(req, (char *)headerbuf, smb_maxcnt);
+               setup_readX_header((char *)headerbuf, smb_maxcnt);
 
                /* Send out the header. */
                ret = write_data(xconn->transport.sock, (char *)headerbuf,
@@ -3994,7 +4151,7 @@ normal_read:
                        errno = saved_errno;
                        exit_server_cleanly("send_file_readX: fake_sendfile failed");
                }
-               goto strict_unlock;
+               goto out;
        }
 
 nosendfile_read:
@@ -4007,21 +4164,18 @@ nosendfile_read:
                          startpos, smb_maxcnt);
        saved_errno = errno;
 
-       SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-
        if (nread < 0) {
                reply_nterror(req, map_nt_error_from_unix(saved_errno));
                return;
        }
 
-       setup_readX_header(req, (char *)req->outbuf, nread);
+       setup_readX_header((char *)req->outbuf, nread);
 
        DEBUG(3, ("send_file_readX %s max=%d nread=%d\n",
                  fsp_fnum_dbg(fsp), (int)smb_maxcnt, (int)nread));
        return;
 
- strict_unlock:
-       SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
+out:
        TALLOC_FREE(req->outbuf);
        return;
 }
@@ -4331,6 +4485,9 @@ void reply_writebraw(struct smb_request *req)
        }
 
        /* Ensure we don't write bytes past the end of this packet. */
+       /*
+        * This already protects us against CVE-2017-12163.
+        */
        if (data + numtowrite > smb_base(req->inbuf) + smb_len(req->inbuf)) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                error_to_writebrawerr(req);
@@ -4343,7 +4500,7 @@ void reply_writebraw(struct smb_request *req)
                    (uint64_t)startpos, (uint64_t)tcount, WRITE_LOCK,
                    &lock);
 
-               if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+               if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                        reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        error_to_writebrawerr(req);
                        END_PROFILE(SMBwritebraw);
@@ -4363,7 +4520,7 @@ void reply_writebraw(struct smb_request *req)
        if (nwritten < (ssize_t)numtowrite)  {
                reply_nterror(req, NT_STATUS_DISK_FULL);
                error_to_writebrawerr(req);
-               goto strict_unlock;
+               goto out;
        }
 
        total_written = nwritten;
@@ -4373,7 +4530,7 @@ void reply_writebraw(struct smb_request *req)
        if (!buf) {
                reply_nterror(req, NT_STATUS_NO_MEMORY);
                error_to_writebrawerr(req);
-               goto strict_unlock;
+               goto out;
        }
 
        /* Return a SMBwritebraw message to the redirector to tell
@@ -4431,12 +4588,17 @@ void reply_writebraw(struct smb_request *req)
                        exit_server_cleanly("secondary writebraw failed");
                }
 
+               /*
+                * We are not vulnerable to CVE-2017-12163
+                * here as we are guarenteed to have numtowrite
+                * bytes available - we just read from the client.
+                */
                nwritten = write_file(req,fsp,buf+4,startpos+nwritten,numtowrite);
                if (nwritten == -1) {
                        TALLOC_FREE(buf);
                        reply_nterror(req, map_nt_error_from_unix(errno));
                        error_to_writebrawerr(req);
-                       goto strict_unlock;
+                       goto out;
                }
 
                if (nwritten < (ssize_t)numtowrite) {
@@ -4458,7 +4620,7 @@ void reply_writebraw(struct smb_request *req)
                         fsp_str_dbg(fsp), nt_errstr(status)));
                reply_nterror(req, status);
                error_to_writebrawerr(req);
-               goto strict_unlock;
+               goto out;
        }
 
        DEBUG(3,("reply_writebraw: secondart write %s start=%.0f num=%d "
@@ -4466,10 +4628,6 @@ void reply_writebraw(struct smb_request *req)
                fsp_fnum_dbg(fsp), (double)startpos, (int)numtowrite,
                (int)total_written));
 
-       if (!fsp->print_file) {
-               SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-       }
-
        /* We won't return a status if write through is not selected - this
         * follows what WfWg does */
        END_PROFILE(SMBwritebraw);
@@ -4491,11 +4649,7 @@ void reply_writebraw(struct smb_request *req)
        }
        return;
 
-strict_unlock:
-       if (!fsp->print_file) {
-               SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-       }
-
+out:
        END_PROFILE(SMBwritebraw);
        return;
 }
@@ -4512,6 +4666,7 @@ void reply_writeunlock(struct smb_request *req)
        connection_struct *conn = req->conn;
        ssize_t nwritten = -1;
        size_t numtowrite;
+       size_t remaining;
        off_t startpos;
        const char *data;
        NTSTATUS status = NT_STATUS_OK;
@@ -4544,12 +4699,23 @@ void reply_writeunlock(struct smb_request *req)
        startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
        data = (const char *)req->buf + 3;
 
+       /*
+        * Ensure client isn't asking us to write more than
+        * they sent. CVE-2017-12163.
+        */
+       remaining = smbreq_bufrem(req, data);
+       if (numtowrite > remaining) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBwriteunlock);
+               return;
+       }
+
        if (!fsp->print_file && numtowrite > 0) {
                init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
                    (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
                    &lock);
 
-               if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+               if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                        reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        END_PROFILE(SMBwriteunlock);
                        return;
@@ -4571,17 +4737,17 @@ void reply_writeunlock(struct smb_request *req)
                DEBUG(5,("reply_writeunlock: sync_file for %s returned %s\n",
                         fsp_str_dbg(fsp), nt_errstr(status)));
                reply_nterror(req, status);
-               goto strict_unlock;
+               goto out;
        }
 
        if(nwritten < 0) {
                reply_nterror(req, map_nt_error_from_unix(saved_errno));
-               goto strict_unlock;
+               goto out;
        }
 
        if((nwritten < numtowrite) && (numtowrite != 0)) {
                reply_nterror(req, NT_STATUS_DISK_FULL);
-               goto strict_unlock;
+               goto out;
        }
 
        if (numtowrite && !fsp->print_file) {
@@ -4594,7 +4760,7 @@ void reply_writeunlock(struct smb_request *req)
 
                if (NT_STATUS_V(status)) {
                        reply_nterror(req, status);
-                       goto strict_unlock;
+                       goto out;
                }
        }
 
@@ -4605,11 +4771,7 @@ void reply_writeunlock(struct smb_request *req)
        DEBUG(3, ("writeunlock %s num=%d wrote=%d\n",
                  fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
 
-strict_unlock:
-       if (numtowrite && !fsp->print_file) {
-               SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-       }
-
+out:
        END_PROFILE(SMBwriteunlock);
        return;
 }
@@ -4625,6 +4787,7 @@ void reply_write(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
        size_t numtowrite;
+       size_t remaining;
        ssize_t nwritten = -1;
        off_t startpos;
        const char *data;
@@ -4665,12 +4828,23 @@ void reply_write(struct smb_request *req)
        startpos = IVAL_TO_SMB_OFF_T(req->vwv+2, 0);
        data = (const char *)req->buf + 3;
 
+       /*
+        * Ensure client isn't asking us to write more than
+        * they sent. CVE-2017-12163.
+        */
+       remaining = smbreq_bufrem(req, data);
+       if (numtowrite > remaining) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBwrite);
+               return;
+       }
+
        if (!fsp->print_file) {
                init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
                        (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
                        &lock);
 
-               if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+               if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                        reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        END_PROFILE(SMBwrite);
                        return;
@@ -4690,12 +4864,12 @@ void reply_write(struct smb_request *req)
                nwritten = vfs_allocate_file_space(fsp, (off_t)startpos);
                if (nwritten < 0) {
                        reply_nterror(req, NT_STATUS_DISK_FULL);
-                       goto strict_unlock;
+                       goto out;
                }
                nwritten = vfs_set_filelen(fsp, (off_t)startpos);
                if (nwritten < 0) {
                        reply_nterror(req, NT_STATUS_DISK_FULL);
-                       goto strict_unlock;
+                       goto out;
                }
                trigger_write_time_update_immediate(fsp);
        } else {
@@ -4707,17 +4881,17 @@ void reply_write(struct smb_request *req)
                DEBUG(5,("reply_write: sync_file for %s returned %s\n",
                         fsp_str_dbg(fsp), nt_errstr(status)));
                reply_nterror(req, status);
-               goto strict_unlock;
+               goto out;
        }
 
        if(nwritten < 0) {
                reply_nterror(req, map_nt_error_from_unix(saved_errno));
-               goto strict_unlock;
+               goto out;
        }
 
        if((nwritten == 0) && (numtowrite != 0)) {
                reply_nterror(req, NT_STATUS_DISK_FULL);
-               goto strict_unlock;
+               goto out;
        }
 
        reply_outbuf(req, 1, 0);
@@ -4731,11 +4905,7 @@ void reply_write(struct smb_request *req)
 
        DEBUG(3, ("write %s num=%d wrote=%d\n", fsp_fnum_dbg(fsp), (int)numtowrite, (int)nwritten));
 
-strict_unlock:
-       if (!fsp->print_file) {
-               SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-       }
-
+out:
        END_PROFILE(SMBwrite);
        return;
 }
@@ -4891,6 +5061,9 @@ void reply_write_and_X(struct smb_request *req)
                        goto out;
                }
        } else {
+               /*
+                * This already protects us against CVE-2017-12163.
+                */
                if (smb_doff > smblen || smb_doff + numtowrite < numtowrite ||
                                smb_doff + numtowrite > smblen) {
                        reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
@@ -4963,15 +5136,13 @@ void reply_write_and_X(struct smb_request *req)
                    (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
                    &lock);
 
-               if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+               if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                        reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        goto out;
                }
 
                nwritten = write_file(req,fsp,data,startpos,numtowrite);
                saved_errno = errno;
-
-               SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
        }
 
        if(nwritten < 0) {
@@ -5105,6 +5276,23 @@ void reply_lseek(struct smb_request *req)
        return;
 }
 
+static struct files_struct *file_sync_one_fn(struct files_struct *fsp,
+                                            void *private_data)
+{
+       connection_struct *conn = talloc_get_type_abort(
+               private_data, connection_struct);
+
+       if (conn != fsp->conn) {
+               return NULL;
+       }
+       if (fsp->fh->fd == -1) {
+               return NULL;
+       }
+       sync_file(conn, fsp, True /* write through */);
+
+       return NULL;
+}
+
 /****************************************************************************
  Reply to a flush.
 ****************************************************************************/
@@ -5130,7 +5318,7 @@ void reply_flush(struct smb_request *req)
        }
 
        if (!fsp) {
-               file_sync_all(conn);
+               files_forall(req->sconn, file_sync_one_fn, conn);
        } else {
                NTSTATUS status = sync_file(conn, fsp, True);
                if (!NT_STATUS_IS_OK(status)) {
@@ -5229,7 +5417,7 @@ void reply_close(struct smb_request *req)
                 */
 
                fsp->deferred_close = tevent_wait_send(
-                       fsp, fsp->conn->sconn->ev_ctx);
+                       fsp, req->ev_ctx);
                if (fsp->deferred_close == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto done;
@@ -5319,6 +5507,7 @@ void reply_writeclose(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
        size_t numtowrite;
+       size_t remaining;
        ssize_t nwritten = -1;
        NTSTATUS close_status = NT_STATUS_OK;
        off_t startpos;
@@ -5352,12 +5541,23 @@ void reply_writeclose(struct smb_request *req)
        mtime = convert_time_t_to_timespec(srv_make_unix_date3(req->vwv+4));
        data = (const char *)req->buf + 1;
 
+       /*
+        * Ensure client isn't asking us to write more than
+        * they sent. CVE-2017-12163.
+        */
+       remaining = smbreq_bufrem(req, data);
+       if (numtowrite > remaining) {
+               reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
+               END_PROFILE(SMBwriteclose);
+               return;
+       }
+
        if (fsp->print_file == NULL) {
                init_strict_lock_struct(fsp, (uint64_t)req->smbpid,
                    (uint64_t)startpos, (uint64_t)numtowrite, WRITE_LOCK,
                    &lock);
 
-               if (!SMB_VFS_STRICT_LOCK(conn, fsp, &lock)) {
+               if (!SMB_VFS_STRICT_LOCK_CHECK(conn, fsp, &lock)) {
                        reply_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
                        END_PROFILE(SMBwriteclose);
                        return;
@@ -5366,10 +5566,6 @@ void reply_writeclose(struct smb_request *req)
 
        nwritten = write_file(req,fsp,data,startpos,numtowrite);
 
-       if (fsp->print_file == NULL) {
-               SMB_VFS_STRICT_UNLOCK(conn, fsp, &lock);
-       }
-
        set_close_write_time(fsp, mtime);
 
        /*
@@ -5792,10 +5988,11 @@ void reply_printqueue(struct smb_request *req)
 
                ZERO_STRUCT(handle);
 
-               status = rpc_pipe_open_interface(conn,
+               status = rpc_pipe_open_interface(mem_ctx,
                                                 &ndr_table_spoolss,
                                                 conn->session_info,
                                                 conn->sconn->remote_address,
+                                                conn->sconn->local_address,
                                                 conn->sconn->msg_ctx,
                                                 &cli);
                if (!NT_STATUS_IS_OK(status)) {
@@ -5947,6 +6144,9 @@ void reply_printwrite(struct smb_request *req)
 
        numtowrite = SVAL(req->buf, 1);
 
+       /*
+        * This already protects us against CVE-2017-12163.
+        */
        if (req->buflen < numtowrite + 3) {
                reply_nterror(req, NT_STATUS_INVALID_PARAMETER);
                END_PROFILE(SMBsplwr);
@@ -5977,8 +6177,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 |
-                       (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags;
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBmkdir);
@@ -5990,11 +6189,12 @@ 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,
                                 ucf_flags,
                                 NULL,
+                                NULL,
                                 &smb_dname);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -6049,7 +6249,7 @@ void reply_rmdir(struct smb_request *req)
        TALLOC_CTX *ctx = talloc_tos();
        files_struct *fsp = NULL;
        int info = 0;
-       uint32_t ucf_flags = (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
        struct smbd_server_connection *sconn = req->sconn;
 
        START_PROFILE(SMBrmdir);
@@ -6062,10 +6262,10 @@ void reply_rmdir(struct smb_request *req)
        }
 
        status = filename_convert(ctx, conn,
-                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                 directory,
                                 ucf_flags,
                                 NULL,
+                                NULL,
                                 &smb_dname);
        if (!NT_STATUS_IS_OK(status)) {
                if (NT_STATUS_EQUAL(status,NT_STATUS_PATH_NOT_COVERED)) {
@@ -6457,9 +6657,10 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
        struct smb_filename *smb_fname_dst = NULL;
        NTSTATUS status = NT_STATUS_OK;
        struct share_mode_lock *lck = NULL;
+       uint32_t access_mask = SEC_DIR_ADD_FILE;
        bool dst_exists, old_is_stream, new_is_stream;
 
-       status = check_name(conn, smb_fname_dst_in->base_name);
+       status = check_name(conn, smb_fname_dst_in);
        if (!NT_STATUS_IS_OK(status)) {
                return status;
        }
@@ -6469,6 +6670,10 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                return status;
        }
 
+       if (file_has_open_streams(fsp)) {
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        /* Make a copy of the dst smb_fname structs */
 
        smb_fname_dst = cp_smb_filename(ctx, smb_fname_dst_in);
@@ -6487,59 +6692,75 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
        if (!conn->case_sensitive && conn->case_preserve &&
            strequal(fsp->fsp_name->base_name, smb_fname_dst->base_name) &&
            strequal(fsp->fsp_name->stream_name, smb_fname_dst->stream_name)) {
-               char *last_slash;
-               char *fname_dst_lcomp_base_mod = NULL;
-               struct smb_filename *smb_fname_orig_lcomp = NULL;
+               char *fname_dst_parent = NULL;
+               const char *fname_dst_lcomp = NULL;
+               char *orig_lcomp_path = NULL;
+               char *orig_lcomp_stream = NULL;
+               bool ok = true;
 
                /*
-                * Get the last component of the destination name.
+                * Split off the last component of the processed
+                * destination name. We will compare this to
+                * the split components of smb_fname_dst->original_lcomp.
                 */
-               last_slash = strrchr_m(smb_fname_dst->base_name, '/');
-               if (last_slash) {
-                       fname_dst_lcomp_base_mod = talloc_strdup(ctx, last_slash + 1);
-               } else {
-                       fname_dst_lcomp_base_mod = talloc_strdup(ctx, smb_fname_dst->base_name);
-               }
-               if (!fname_dst_lcomp_base_mod) {
+               if (!parent_dirname(ctx,
+                               smb_fname_dst->base_name,
+                               &fname_dst_parent,
+                               &fname_dst_lcomp)) {
                        status = NT_STATUS_NO_MEMORY;
                        goto out;
                }
 
                /*
-                * Create an smb_filename struct using the original last
-                * component of the destination.
+                * The original_lcomp component contains
+                * the last_component of the path + stream
+                * name (if a stream exists).
+                *
+                * Split off the stream name so we
+                * can check them separately.
                 */
-               smb_fname_orig_lcomp = synthetic_smb_fname_split(
-                       ctx, smb_fname_dst->original_lcomp, NULL);
-               if (smb_fname_orig_lcomp == NULL) {
+
+               if (fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) {
+                       /* POSIX - no stream component. */
+                       orig_lcomp_path = talloc_strdup(ctx,
+                                               smb_fname_dst->original_lcomp);
+                       if (orig_lcomp_path == NULL) {
+                               ok = false;
+                       }
+               } else {
+                       ok = split_stream_filename(ctx,
+                                       smb_fname_dst->original_lcomp,
+                                       &orig_lcomp_path,
+                                       &orig_lcomp_stream);
+               }
+
+               if (!ok) {
+                       TALLOC_FREE(fname_dst_parent);
                        status = NT_STATUS_NO_MEMORY;
-                       TALLOC_FREE(fname_dst_lcomp_base_mod);
                        goto out;
                }
 
                /* If the base names only differ by case, use original. */
-               if(!strcsequal(fname_dst_lcomp_base_mod,
-                              smb_fname_orig_lcomp->base_name)) {
+               if(!strcsequal(fname_dst_lcomp, orig_lcomp_path)) {
                        char *tmp;
                        /*
                         * Replace the modified last component with the
                         * original.
                         */
-                       if (last_slash) {
-                               *last_slash = '\0'; /* Truncate at the '/' */
+                       if (!ISDOT(fname_dst_parent)) {
                                tmp = talloc_asprintf(smb_fname_dst,
                                        "%s/%s",
-                                       smb_fname_dst->base_name,
-                                       smb_fname_orig_lcomp->base_name);
+                                       fname_dst_parent,
+                                       orig_lcomp_path);
                        } else {
-                               tmp = talloc_asprintf(smb_fname_dst,
-                                       "%s",
-                                       smb_fname_orig_lcomp->base_name);
+                               tmp = talloc_strdup(smb_fname_dst,
+                                       orig_lcomp_path);
                        }
                        if (tmp == NULL) {
                                status = NT_STATUS_NO_MEMORY;
-                               TALLOC_FREE(fname_dst_lcomp_base_mod);
-                               TALLOC_FREE(smb_fname_orig_lcomp);
+                               TALLOC_FREE(fname_dst_parent);
+                               TALLOC_FREE(orig_lcomp_path);
+                               TALLOC_FREE(orig_lcomp_stream);
                                goto out;
                        }
                        TALLOC_FREE(smb_fname_dst->base_name);
@@ -6548,22 +6769,23 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 
                /* If the stream_names only differ by case, use original. */
                if(!strcsequal(smb_fname_dst->stream_name,
-                              smb_fname_orig_lcomp->stream_name)) {
-                       char *tmp = NULL;
+                              orig_lcomp_stream)) {
                        /* Use the original stream. */
-                       tmp = talloc_strdup(smb_fname_dst,
-                                           smb_fname_orig_lcomp->stream_name);
+                       char *tmp = talloc_strdup(smb_fname_dst,
+                                           orig_lcomp_stream);
                        if (tmp == NULL) {
                                status = NT_STATUS_NO_MEMORY;
-                               TALLOC_FREE(fname_dst_lcomp_base_mod);
-                               TALLOC_FREE(smb_fname_orig_lcomp);
+                               TALLOC_FREE(fname_dst_parent);
+                               TALLOC_FREE(orig_lcomp_path);
+                               TALLOC_FREE(orig_lcomp_stream);
                                goto out;
                        }
                        TALLOC_FREE(smb_fname_dst->stream_name);
                        smb_fname_dst->stream_name = tmp;
                }
-               TALLOC_FREE(fname_dst_lcomp_base_mod);
-               TALLOC_FREE(smb_fname_orig_lcomp);
+               TALLOC_FREE(fname_dst_parent);
+               TALLOC_FREE(orig_lcomp_path);
+               TALLOC_FREE(orig_lcomp_stream);
        }
 
        /*
@@ -6637,6 +6859,23 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
 
        if (rename_path_prefix_equal(fsp->fsp_name, smb_fname_dst)) {
                status = NT_STATUS_ACCESS_DENIED;
+               goto out;
+       }
+
+       /* Do we have rights to move into the destination ? */
+       if (S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+               /* We're moving a directory. */
+               access_mask = SEC_DIR_ADD_SUBDIR;
+       }
+       status = check_parent_access(conn,
+                               smb_fname_dst,
+                               access_mask);
+       if (!NT_STATUS_IS_OK(status)) {
+               DBG_INFO("check_parent_access on "
+                       "dst %s returned %s\n",
+                       smb_fname_str_dbg(smb_fname_dst),
+                       nt_errstr(status));
+               goto out;
        }
 
        lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
@@ -6656,7 +6895,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                          smb_fname_str_dbg(smb_fname_dst)));
 
                if (!fsp->is_directory &&
-                   !lp_posix_pathnames() &&
+                   !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
                    (lp_map_archive(SNUM(conn)) ||
                    lp_store_dos_attributes(SNUM(conn)))) {
                        /* We must set the archive bit on the newly
@@ -6691,7 +6930,7 @@ NTSTATUS rename_internals_fsp(connection_struct *conn,
                        status = can_set_delete_on_close(fsp, 0);
 
                        if (NT_STATUS_IS_OK(status)) {
-                               /* Note that here we set the *inital* delete on close flag,
+                               /* Note that here we set the *initial* delete on close flag,
                                 * not the regular one. The magic gets handled in close. */
                                fsp->initial_delete_on_close = True;
                        }
@@ -6736,6 +6975,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                        uint32_t access_mask)
 {
        char *fname_src_dir = NULL;
+       struct smb_filename *smb_fname_src_dir = NULL;
        char *fname_src_mask = NULL;
        int count=0;
        NTSTATUS status = NT_STATUS_OK;
@@ -6744,7 +6984,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
        char *talloced = NULL;
        long offset = 0;
        int create_options = 0;
-       bool posix_pathnames = lp_posix_pathnames();
+       bool posix_pathnames = (req != NULL && req->posix_pathnames);
        int rc;
 
        /*
@@ -6903,12 +7143,22 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
                }
        }
 
-       status = check_name(conn, fname_src_dir);
+       smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
+                               fname_src_dir,
+                               NULL,
+                               NULL,
+                               smb_fname_src->flags);
+       if (smb_fname_src_dir == NULL) {
+               status = NT_STATUS_NO_MEMORY;
+               goto out;
+       }
+
+       status = check_name(conn, smb_fname_src_dir);
        if (!NT_STATUS_IS_OK(status)) {
                goto out;
        }
 
-       dir_hnd = OpenDir(talloc_tos(), conn, fname_src_dir, fname_src_mask,
+       dir_hnd = OpenDir(talloc_tos(), conn, smb_fname_src_dir, fname_src_mask,
                          attrs);
        if (dir_hnd == NULL) {
                status = map_nt_error_from_unix(errno);
@@ -7064,6 +7314,7 @@ NTSTATUS rename_internals(TALLOC_CTX *ctx,
 
  out:
        TALLOC_FREE(talloced);
+       TALLOC_FREE(smb_fname_src_dir);
        TALLOC_FREE(fname_src_dir);
        TALLOC_FREE(fname_src_mask);
        return status;
@@ -7086,12 +7337,15 @@ void reply_mv(struct smb_request *req)
        TALLOC_CTX *ctx = talloc_tos();
        struct smb_filename *smb_fname_src = NULL;
        struct smb_filename *smb_fname_dst = NULL;
-       uint32_t src_ucf_flags = (lp_posix_pathnames() ?
-               (UCF_UNIX_NAME_LOOKUP|UCF_POSIX_PATHNAMES) :
-               UCF_COND_ALLOW_WCARD_LCOMP);
-       uint32_t dst_ucf_flags = UCF_SAVE_LCOMP |
-               (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES :
-                UCF_COND_ALLOW_WCARD_LCOMP);
+       uint32_t src_ucf_flags = ucf_flags_from_smb_request(req) |
+               (req->posix_pathnames ?
+                       UCF_UNIX_NAME_LOOKUP :
+                       UCF_COND_ALLOW_WCARD_LCOMP);
+       uint32_t dst_ucf_flags = ucf_flags_from_smb_request(req) |
+               UCF_SAVE_LCOMP |
+               (req->posix_pathnames ?
+                       0 :
+                       UCF_COND_ALLOW_WCARD_LCOMP);
        bool stream_rename = false;
 
        START_PROFILE(SMBmv);
@@ -7118,7 +7372,7 @@ void reply_mv(struct smb_request *req)
                goto out;
        }
 
-       if (!lp_posix_pathnames()) {
+       if (!req->posix_pathnames) {
                /* The newname must begin with a ':' if the
                   name contains a ':'. */
                if (strchr_m(name, ':')) {
@@ -7132,9 +7386,9 @@ void reply_mv(struct smb_request *req)
 
        status = filename_convert(ctx,
                                  conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  name,
                                  src_ucf_flags,
+                                 NULL,
                                  &src_has_wcard,
                                  &smb_fname_src);
 
@@ -7150,9 +7404,9 @@ void reply_mv(struct smb_request *req)
 
        status = filename_convert(ctx,
                                  conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  newname,
                                  dst_ucf_flags,
+                                 NULL,
                                  &dest_has_wcard,
                                  &smb_fname_dst);
 
@@ -7387,6 +7641,7 @@ void reply_copy(struct smb_request *req)
 {
        connection_struct *conn = req->conn;
        struct smb_filename *smb_fname_src = NULL;
+       struct smb_filename *smb_fname_src_dir = NULL;
        struct smb_filename *smb_fname_dst = NULL;
        char *fname_src = NULL;
        char *fname_dst = NULL;
@@ -7403,9 +7658,9 @@ void reply_copy(struct smb_request *req)
        bool dest_has_wild = False;
        NTSTATUS status;
        uint32_t ucf_flags_src = UCF_COND_ALLOW_WCARD_LCOMP |
-               (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+               ucf_flags_from_smb_request(req);
        uint32_t ucf_flags_dst = UCF_COND_ALLOW_WCARD_LCOMP |
-               (lp_posix_pathnames() ? UCF_POSIX_PATHNAMES : 0);
+               ucf_flags_from_smb_request(req);
        TALLOC_CTX *ctx = talloc_tos();
 
        START_PROFILE(SMBcopy);
@@ -7443,9 +7698,9 @@ void reply_copy(struct smb_request *req)
        }
 
        status = filename_convert(ctx, conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  fname_src,
                                  ucf_flags_src,
+                                 NULL,
                                  &source_has_wild,
                                  &smb_fname_src);
        if (!NT_STATUS_IS_OK(status)) {
@@ -7459,9 +7714,9 @@ void reply_copy(struct smb_request *req)
        }
 
        status = filename_convert(ctx, conn,
-                                 req->flags2 & FLAGS2_DFS_PATHNAMES,
                                  fname_dst,
                                  ucf_flags_dst,
+                                 NULL,
                                  &dest_has_wild,
                                  &smb_fname_dst);
        if (!NT_STATUS_IS_OK(status)) {
@@ -7558,13 +7813,13 @@ void reply_copy(struct smb_request *req)
                        smb_fname_dst->base_name = fname_dst_mod;
                }
 
-               status = check_name(conn, smb_fname_src->base_name);
+               status = check_name(conn, smb_fname_src);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        goto out;
                }
 
-               status = check_name(conn, smb_fname_dst->base_name);
+               status = check_name(conn, smb_fname_dst);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        goto out;
@@ -7606,13 +7861,27 @@ void reply_copy(struct smb_request *req)
                        }
                }
 
-               status = check_name(conn, fname_src_dir);
+               smb_fname_src_dir = synthetic_smb_fname(talloc_tos(),
+                                       fname_src_dir,
+                                       NULL,
+                                       NULL,
+                                       smb_fname_src->flags);
+               if (smb_fname_src_dir == NULL) {
+                       reply_nterror(req, NT_STATUS_NO_MEMORY);
+                       goto out;
+               }
+
+               status = check_name(conn, smb_fname_src_dir);
                if (!NT_STATUS_IS_OK(status)) {
                        reply_nterror(req, status);
                        goto out;
                }
 
-               dir_hnd = OpenDir(ctx, conn, fname_src_dir, fname_src_mask, 0);
+               dir_hnd = OpenDir(ctx,
+                               conn,
+                               smb_fname_src_dir,
+                               fname_src_mask,
+                               0);
                if (dir_hnd == NULL) {
                        status = map_nt_error_from_unix(errno);
                        reply_nterror(req, status);
@@ -7681,7 +7950,7 @@ void reply_copy(struct smb_request *req)
                        TALLOC_FREE(smb_fname_dst->base_name);
                        smb_fname_dst->base_name = destname;
 
-                       status = check_name(conn, smb_fname_src->base_name);
+                       status = check_name(conn, smb_fname_src);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                TALLOC_FREE(talloced);
@@ -7689,7 +7958,7 @@ void reply_copy(struct smb_request *req)
                                goto out;
                        }
 
-                       status = check_name(conn, smb_fname_dst->base_name);
+                       status = check_name(conn, smb_fname_dst);
                        if (!NT_STATUS_IS_OK(status)) {
                                TALLOC_FREE(dir_hnd);
                                TALLOC_FREE(talloced);
@@ -7722,6 +7991,7 @@ void reply_copy(struct smb_request *req)
        SSVAL(req->outbuf,smb_vwv0,count);
  out:
        TALLOC_FREE(smb_fname_src);
+       TALLOC_FREE(smb_fname_src_dir);
        TALLOC_FREE(smb_fname_dst);
        TALLOC_FREE(fname_src);
        TALLOC_FREE(fname_dst);