smbd: Pass "file_id" explicitly to send_break_message()
[samba.git] / source3 / smbd / open.c
index f5ad900f749a892015e8dd625de4c02861179131..be9e601bb1518dc07babdbcd8605f43c50263c4a 100644 (file)
@@ -4,6 +4,7 @@
    Copyright (C) Andrew Tridgell 1992-1998
    Copyright (C) Jeremy Allison 2001-2004
    Copyright (C) Volker Lendecke 2005
+   Copyright (C) Ralph Boehme 2017
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -21,6 +22,7 @@
 
 #include "includes.h"
 #include "system/filesys.h"
+#include "lib/util/server_id.h"
 #include "printing.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
@@ -36,6 +38,7 @@
 #include "messages.h"
 #include "source3/lib/dbwrap/dbwrap_watch.h"
 #include "locking/leases_db.h"
+#include "librpc/gen_ndr/ndr_leases_db.h"
 
 extern const struct generic_mapping file_generic_mapping;
 
@@ -43,6 +46,13 @@ struct deferred_open_record {
         bool delayed_for_oplocks;
        bool async_open;
         struct file_id id;
+
+       /*
+        * Timer for async opens, needed because they don't use a watch on
+        * a locking.tdb record. This is currently only used for real async
+        * opens and just terminates smbd if the async open times out.
+        */
+       struct tevent_timer *te;
 };
 
 /****************************************************************************
@@ -118,7 +128,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
                return NT_STATUS_OK;
        }
 
-       status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
+       status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
                        (SECINFO_OWNER |
                        SECINFO_GROUP |
                         SECINFO_DACL), talloc_tos(), &sd);
@@ -152,7 +162,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
         * Samba 3.6 and earlier granted execute access even
         * if the ACL did not contain execute rights.
         * Samba 4.0 is more correct and checks it.
-        * The compatibilty mode allows to skip this check
+        * The compatibilty mode allows one to skip this check
         * to smoothen upgrades.
         */
        if (lp_acl_allow_execute_always(SNUM(conn))) {
@@ -234,7 +244,7 @@ NTSTATUS smbd_check_access_rights(struct connection_struct *conn,
        return NT_STATUS_OK;
 }
 
-static NTSTATUS check_parent_access(struct connection_struct *conn,
+NTSTATUS check_parent_access(struct connection_struct *conn,
                                struct smb_filename *smb_fname,
                                uint32_t access_mask)
 {
@@ -242,6 +252,12 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
        char *parent_dir = NULL;
        struct security_descriptor *parent_sd = NULL;
        uint32_t access_granted = 0;
+       struct smb_filename *parent_smb_fname = NULL;
+       struct share_mode_lock *lck = NULL;
+       struct file_id id = {0};
+       uint32_t name_hash;
+       bool delete_on_close_set;
+       int ret;
 
        if (!parent_dirname(talloc_tos(),
                                smb_fname->base_name,
@@ -250,6 +266,15 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
                return NT_STATUS_NO_MEMORY;
        }
 
+       parent_smb_fname = synthetic_smb_fname(talloc_tos(),
+                               parent_dir,
+                               NULL,
+                               NULL,
+                               smb_fname->flags);
+       if (parent_smb_fname == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
        if (get_current_uid(conn) == (uid_t)0) {
                /* I'm sorry sir, I didn't know you were root... */
                DEBUG(10,("check_parent_access: root override "
@@ -260,7 +285,7 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
        }
 
        status = SMB_VFS_GET_NT_ACL(conn,
-                               parent_dir,
+                               parent_smb_fname,
                                SECINFO_DACL,
                                    talloc_tos(),
                                &parent_sd);
@@ -300,7 +325,45 @@ static NTSTATUS check_parent_access(struct connection_struct *conn,
                return status;
        }
 
-       return NT_STATUS_OK;
+       if (!(access_mask & (SEC_DIR_ADD_FILE | SEC_DIR_ADD_SUBDIR))) {
+               return NT_STATUS_OK;
+       }
+       if (!lp_check_parent_directory_delete_on_close(SNUM(conn))) {
+               return NT_STATUS_OK;
+       }
+
+       /* Check if the directory has delete-on-close set */
+       ret = SMB_VFS_STAT(conn, parent_smb_fname);
+       if (ret != 0) {
+               status = map_nt_error_from_unix(errno);
+               goto out;
+       }
+
+       id = SMB_VFS_FILE_ID_CREATE(conn, &parent_smb_fname->st);
+
+       status = file_name_hash(conn, parent_smb_fname->base_name, &name_hash);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto out;
+       }
+
+       lck = get_existing_share_mode_lock(talloc_tos(), id);
+       if (lck == NULL) {
+               status = NT_STATUS_OK;
+               goto out;
+       }
+
+       delete_on_close_set = is_delete_on_close_set(lck, name_hash);
+       if (delete_on_close_set) {
+               status = NT_STATUS_DELETE_PENDING;
+               goto out;
+       }
+
+       status = NT_STATUS_OK;
+
+out:
+       TALLOC_FREE(lck);
+       TALLOC_FREE(parent_smb_fname);
+       return status;
 }
 
 /****************************************************************************
@@ -343,6 +406,326 @@ static NTSTATUS check_base_file_access(struct connection_struct *conn,
                                        access_mask);
 }
 
+/****************************************************************************
+ Handle differing symlink errno's
+****************************************************************************/
+
+static int link_errno_convert(int err)
+{
+#if defined(ENOTSUP) && defined(OSF1)
+       /* handle special Tru64 errno */
+       if (err == ENOTSUP) {
+               err = ELOOP;
+       }
+#endif /* ENOTSUP */
+#ifdef EFTYPE
+       /* fix broken NetBSD errno */
+       if (err == EFTYPE) {
+               err = ELOOP;
+       }
+#endif /* EFTYPE */
+       /* fix broken FreeBSD errno */
+       if (err == EMLINK) {
+               err = ELOOP;
+       }
+       return err;
+}
+
+static int non_widelink_open(struct connection_struct *conn,
+                       const struct smb_filename *conn_rootdir_fname,
+                       files_struct *fsp,
+                       struct smb_filename *smb_fname,
+                       int flags,
+                       mode_t mode,
+                       unsigned int link_depth);
+
+/****************************************************************************
+ Follow a symlink in userspace.
+****************************************************************************/
+
+static int process_symlink_open(struct connection_struct *conn,
+                       const struct smb_filename *conn_rootdir_fname,
+                       files_struct *fsp,
+                       struct smb_filename *smb_fname,
+                       int flags,
+                       mode_t mode,
+                       unsigned int link_depth)
+{
+       int fd = -1;
+       char *link_target = NULL;
+       struct smb_filename target_fname = {0};
+       int link_len = -1;
+       struct smb_filename *oldwd_fname = NULL;
+       size_t rootdir_len = 0;
+       struct smb_filename *resolved_fname = NULL;
+       char *resolved_name = NULL;
+       bool matched = false;
+       int saved_errno = 0;
+
+       /*
+        * Ensure we don't get stuck in a symlink loop.
+        */
+       link_depth++;
+       if (link_depth >= 20) {
+               errno = ELOOP;
+               goto out;
+       }
+
+       /* Allocate space for the link target. */
+       link_target = talloc_array(talloc_tos(), char, PATH_MAX);
+       if (link_target == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
+
+       /* Read the link target. */
+       link_len = SMB_VFS_READLINK(conn,
+                               smb_fname,
+                               link_target,
+                               PATH_MAX - 1);
+       if (link_len == -1) {
+               goto out;
+       }
+
+       /* Ensure it's at least null terminated. */
+       link_target[link_len] = '\0';
+       target_fname = (struct smb_filename){ .base_name = link_target };
+
+       /* Convert to an absolute path. */
+       resolved_fname = SMB_VFS_REALPATH(conn, talloc_tos(), &target_fname);
+       if (resolved_fname == NULL) {
+               goto out;
+       }
+       resolved_name = resolved_fname->base_name;
+
+       /*
+        * We know conn_rootdir starts with '/' and
+        * does not end in '/'. FIXME ! Should we
+        * smb_assert this ?
+        */
+       rootdir_len = strlen(conn_rootdir_fname->base_name);
+
+       matched = (strncmp(conn_rootdir_fname->base_name,
+                               resolved_name,
+                               rootdir_len) == 0);
+       if (!matched) {
+               errno = EACCES;
+               goto out;
+       }
+
+       /*
+        * Turn into a path relative to the share root.
+        */
+       if (resolved_name[rootdir_len] == '\0') {
+               /* Link to the root of the share. */
+               TALLOC_FREE(smb_fname->base_name);
+               smb_fname->base_name = talloc_strdup(smb_fname, ".");
+       } else if (resolved_name[rootdir_len] == '/') {
+               TALLOC_FREE(smb_fname->base_name);
+               smb_fname->base_name = talloc_strdup(smb_fname,
+                                       &resolved_name[rootdir_len+1]);
+       } else {
+               errno = EACCES;
+               goto out;
+       }
+
+       if (smb_fname->base_name == NULL) {
+               errno = ENOMEM;
+               goto out;
+       }
+
+       oldwd_fname = vfs_GetWd(talloc_tos(), conn);
+       if (oldwd_fname == NULL) {
+               goto out;
+       }
+
+       /* Ensure we operate from the root of the share. */
+       if (vfs_ChDir(conn, conn_rootdir_fname) == -1) {
+               goto out;
+       }
+
+       /* And do it all again.. */
+       fd = non_widelink_open(conn,
+                               conn_rootdir_fname,
+                               fsp,
+                               smb_fname,
+                               flags,
+                               mode,
+                               link_depth);
+       if (fd == -1) {
+               saved_errno = errno;
+       }
+
+  out:
+
+       TALLOC_FREE(resolved_fname);
+       TALLOC_FREE(link_target);
+       if (oldwd_fname != NULL) {
+               int ret = vfs_ChDir(conn, oldwd_fname);
+               if (ret == -1) {
+                       smb_panic("unable to get back to old directory\n");
+               }
+               TALLOC_FREE(oldwd_fname);
+       }
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return fd;
+}
+
+/****************************************************************************
+ Non-widelink open.
+****************************************************************************/
+
+static int non_widelink_open(struct connection_struct *conn,
+                       const struct smb_filename *conn_rootdir_fname,
+                       files_struct *fsp,
+                       struct smb_filename *smb_fname,
+                       int flags,
+                       mode_t mode,
+                       unsigned int link_depth)
+{
+       NTSTATUS status;
+       int fd = -1;
+       struct smb_filename *smb_fname_rel = NULL;
+       int saved_errno = 0;
+       struct smb_filename *oldwd_fname = NULL;
+       char *parent_dir = NULL;
+       struct smb_filename parent_dir_fname = {0};
+       const char *final_component = NULL;
+       bool is_directory = false;
+       bool ok;
+
+#ifdef O_DIRECTORY
+       if (flags & O_DIRECTORY) {
+               is_directory = true;
+       }
+#endif
+
+       if (is_directory) {
+               parent_dir = talloc_strdup(talloc_tos(), smb_fname->base_name);
+               if (parent_dir == NULL) {
+                       saved_errno = errno;
+                       goto out;
+               }
+
+               final_component = ".";
+       } else {
+               ok = parent_dirname(talloc_tos(),
+                                   smb_fname->base_name,
+                                   &parent_dir,
+                                   &final_component);
+               if (!ok) {
+                       saved_errno = errno;
+                       goto out;
+               }
+       }
+
+       parent_dir_fname = (struct smb_filename) { .base_name = parent_dir };
+
+       oldwd_fname = vfs_GetWd(talloc_tos(), conn);
+       if (oldwd_fname == NULL) {
+               goto out;
+       }
+
+       /* Pin parent directory in place. */
+       if (vfs_ChDir(conn, &parent_dir_fname) == -1) {
+               goto out;
+       }
+
+       smb_fname_rel = synthetic_smb_fname(talloc_tos(),
+                               final_component,
+                               smb_fname->stream_name,
+                               &smb_fname->st,
+                               smb_fname->flags);
+       if (smb_fname_rel == NULL) {
+               saved_errno = ENOMEM;
+               goto out;
+       }
+
+       /* Ensure the relative path is below the share. */
+       status = check_reduced_name(conn, &parent_dir_fname, smb_fname_rel);
+       if (!NT_STATUS_IS_OK(status)) {
+               saved_errno = map_errno_from_nt_status(status);
+               goto out;
+       }
+
+       flags |= O_NOFOLLOW;
+
+       {
+               struct smb_filename *tmp_name = fsp->fsp_name;
+               fsp->fsp_name = smb_fname_rel;
+               fd = SMB_VFS_OPEN(conn, smb_fname_rel, fsp, flags, mode);
+               fsp->fsp_name = tmp_name;
+       }
+
+       if (fd == -1) {
+               saved_errno = link_errno_convert(errno);
+               /*
+                * Trying to open a symlink to a directory with O_NOFOLLOW and
+                * O_DIRECTORY can return either of ELOOP and ENOTDIR. So
+                * ENOTDIR really means: might be a symlink, but we're not sure.
+                * In this case, we just assume there's a symlink. If we were
+                * wrong, process_symlink_open() will return EINVAL. We check
+                * this below, and fall back to returning the initial
+                * saved_errno.
+                *
+                * BUG: https://bugzilla.samba.org/show_bug.cgi?id=12860
+                */
+               if (saved_errno == ELOOP || saved_errno == ENOTDIR) {
+                       if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
+                               /* Never follow symlinks on posix open. */
+                               goto out;
+                       }
+                       if (!lp_follow_symlinks(SNUM(conn))) {
+                               /* Explicitly no symlinks. */
+                               goto out;
+                       }
+                       /*
+                        * We may have a symlink. Follow in userspace
+                        * to ensure it's under the share definition.
+                        */
+                       fd = process_symlink_open(conn,
+                                       conn_rootdir_fname,
+                                       fsp,
+                                       smb_fname_rel,
+                                       flags,
+                                       mode,
+                                       link_depth);
+                       if (fd == -1) {
+                               if (saved_errno == ENOTDIR &&
+                                               errno == EINVAL) {
+                                       /*
+                                        * O_DIRECTORY on neither a directory,
+                                        * nor a symlink. Just return
+                                        * saved_errno from initial open()
+                                        */
+                                       goto out;
+                               }
+                               saved_errno =
+                                       link_errno_convert(errno);
+                       }
+               }
+       }
+
+  out:
+
+       TALLOC_FREE(parent_dir);
+       TALLOC_FREE(smb_fname_rel);
+
+       if (oldwd_fname != NULL) {
+               int ret = vfs_ChDir(conn, oldwd_fname);
+               if (ret == -1) {
+                       smb_panic("unable to get back to old directory\n");
+               }
+               TALLOC_FREE(oldwd_fname);
+       }
+       if (saved_errno != 0) {
+               errno = saved_errno;
+       }
+       return fd;
+}
+
 /****************************************************************************
  fd support routines - attempt to do a dos_open.
 ****************************************************************************/
@@ -355,38 +738,58 @@ NTSTATUS fd_open(struct connection_struct *conn,
        struct smb_filename *smb_fname = fsp->fsp_name;
        NTSTATUS status = NT_STATUS_OK;
 
-#ifdef O_NOFOLLOW
-       /* 
+       /*
         * Never follow symlinks on a POSIX client. The
         * client should be doing this.
         */
 
-       if (fsp->posix_open || !lp_follow_symlinks(SNUM(conn))) {
+       if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) {
                flags |= O_NOFOLLOW;
        }
-#endif
 
-       fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
-       if (fsp->fh->fd == -1) {
-               int posix_errno = errno;
-#ifdef O_NOFOLLOW
-#if defined(ENOTSUP) && defined(OSF1)
-               /* handle special Tru64 errno */
-               if (errno == ENOTSUP) {
-                       posix_errno = ELOOP;
+       /* Ensure path is below share definition. */
+       if (!lp_widelinks(SNUM(conn))) {
+               struct smb_filename *conn_rootdir_fname = NULL;
+               const char *conn_rootdir = SMB_VFS_CONNECTPATH(conn,
+                                               smb_fname);
+               int saved_errno = 0;
+
+               if (conn_rootdir == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
-#endif /* ENOTSUP */
-#ifdef EFTYPE
-               /* fix broken NetBSD errno */
-               if (errno == EFTYPE) {
-                       posix_errno = ELOOP;
+               conn_rootdir_fname = synthetic_smb_fname(talloc_tos(),
+                                               conn_rootdir,
+                                               NULL,
+                                               NULL,
+                                               0);
+               if (conn_rootdir_fname == NULL) {
+                       return NT_STATUS_NO_MEMORY;
                }
-#endif /* EFTYPE */
-               /* fix broken FreeBSD errno */
-               if (errno == EMLINK) {
-                       posix_errno = ELOOP;
+
+               /*
+                * Only follow symlinks within a share
+                * definition.
+                */
+               fsp->fh->fd = non_widelink_open(conn,
+                                       conn_rootdir_fname,
+                                       fsp,
+                                       smb_fname,
+                                       flags,
+                                       mode,
+                                       0);
+               if (fsp->fh->fd == -1) {
+                       saved_errno = errno;
+               }
+               TALLOC_FREE(conn_rootdir_fname);
+               if (saved_errno != 0) {
+                       errno = saved_errno;
                }
-#endif /* O_NOFOLLOW */
+       } else {
+               fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
+       }
+
+       if (fsp->fh->fd == -1) {
+               int posix_errno = link_errno_convert(errno);
                status = map_nt_error_from_unix(posix_errno);
                if (errno == EMFILE) {
                        static time_t last_warned = 0L;
@@ -447,8 +850,11 @@ void change_file_owner_to_parent(connection_struct *conn,
        struct smb_filename *smb_fname_parent;
        int ret;
 
-       smb_fname_parent = synthetic_smb_fname(talloc_tos(), inherit_from_dir,
-                                              NULL, NULL);
+       smb_fname_parent = synthetic_smb_fname(talloc_tos(),
+                                       inherit_from_dir,
+                                       NULL,
+                                       NULL,
+                                       0);
        if (smb_fname_parent == NULL) {
                return;
        }
@@ -493,20 +899,23 @@ void change_file_owner_to_parent(connection_struct *conn,
        TALLOC_FREE(smb_fname_parent);
 }
 
-NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
-                                      const char *inherit_from_dir,
-                                      const char *fname,
-                                      SMB_STRUCT_STAT *psbuf)
+static NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
+                                       const char *inherit_from_dir,
+                                       struct smb_filename *smb_dname,
+                                       SMB_STRUCT_STAT *psbuf)
 {
        struct smb_filename *smb_fname_parent;
        struct smb_filename *smb_fname_cwd = NULL;
-       char *saved_dir = NULL;
+       struct smb_filename *saved_dir_fname = NULL;
        TALLOC_CTX *ctx = talloc_tos();
        NTSTATUS status = NT_STATUS_OK;
        int ret;
 
-       smb_fname_parent = synthetic_smb_fname(ctx, inherit_from_dir,
-                                              NULL, NULL);
+       smb_fname_parent = synthetic_smb_fname(ctx,
+                                       inherit_from_dir,
+                                       NULL,
+                                       NULL,
+                                       0);
        if (smb_fname_parent == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -528,8 +937,8 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
           should work on any UNIX (thanks tridge :-). JRA.
        */
 
-       saved_dir = vfs_GetWd(ctx,conn);
-       if (!saved_dir) {
+       saved_dir_fname = vfs_GetWd(ctx,conn);
+       if (!saved_dir_fname) {
                status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to get "
                         "current working directory. Error was %s\n",
@@ -538,15 +947,15 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
        }
 
        /* Chdir into the new path. */
-       if (vfs_ChDir(conn, fname) == -1) {
+       if (vfs_ChDir(conn, smb_dname) == -1) {
                status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to change "
                         "current working directory to %s. Error "
-                        "was %s\n", fname, strerror(errno) ));
+                        "was %s\n", smb_dname->base_name, strerror(errno) ));
                goto chdir;
        }
 
-       smb_fname_cwd = synthetic_smb_fname(ctx, ".", NULL, NULL);
+       smb_fname_cwd = synthetic_smb_fname(ctx, ".", NULL, NULL, 0);
        if (smb_fname_cwd == NULL) {
                status = NT_STATUS_NO_MEMORY;
                goto chdir;
@@ -557,7 +966,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
                status = map_nt_error_from_unix(errno);
                DEBUG(0,("change_dir_owner_to_parent: failed to stat "
                         "directory '.' (%s) Error was %s\n",
-                        fname, strerror(errno)));
+                        smb_dname->base_name, strerror(errno)));
                goto chdir;
        }
 
@@ -566,7 +975,8 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
            smb_fname_cwd->st.st_ex_ino != psbuf->st_ex_ino) {
                DEBUG(0,("change_dir_owner_to_parent: "
                         "device/inode on directory %s changed. "
-                        "Refusing to chown !\n", fname ));
+                        "Refusing to chown !\n",
+                       smb_dname->base_name ));
                status = NT_STATUS_ACCESS_DENIED;
                goto chdir;
        }
@@ -575,34 +985,39 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
                /* Already this uid - no need to change. */
                DEBUG(10,("change_dir_owner_to_parent: directory %s "
                        "is already owned by uid %d\n",
-                       fname,
+                       smb_dname->base_name,
                        (int)smb_fname_cwd->st.st_ex_uid ));
                status = NT_STATUS_OK;
                goto chdir;
        }
 
        become_root();
-       ret = SMB_VFS_LCHOWN(conn, ".", smb_fname_parent->st.st_ex_uid,
-                           (gid_t)-1);
+       ret = SMB_VFS_LCHOWN(conn,
+                       smb_fname_cwd,
+                       smb_fname_parent->st.st_ex_uid,
+                       (gid_t)-1);
        unbecome_root();
        if (ret == -1) {
                status = map_nt_error_from_unix(errno);
                DEBUG(10,("change_dir_owner_to_parent: failed to chown "
                          "directory %s to parent directory uid %u. "
-                         "Error was %s\n", fname,
+                         "Error was %s\n",
+                         smb_dname->base_name,
                          (unsigned int)smb_fname_parent->st.st_ex_uid,
                          strerror(errno) ));
        } else {
                DEBUG(10,("change_dir_owner_to_parent: changed ownership of new "
                        "directory %s to parent directory uid %u.\n",
-                       fname, (unsigned int)smb_fname_parent->st.st_ex_uid ));
+                       smb_dname->base_name,
+                       (unsigned int)smb_fname_parent->st.st_ex_uid ));
                /* Ensure the uid entry is updated. */
                psbuf->st_ex_uid = smb_fname_parent->st.st_ex_uid;
        }
 
  chdir:
-       vfs_ChDir(conn,saved_dir);
+       vfs_ChDir(conn, saved_dir_fname);
  out:
+       TALLOC_FREE(saved_dir_fname);
        TALLOC_FREE(smb_fname_parent);
        TALLOC_FREE(smb_fname_cwd);
        return status;
@@ -620,7 +1035,9 @@ static NTSTATUS fd_open_atomic(struct connection_struct *conn,
                        bool *file_created)
 {
        NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+       NTSTATUS retry_status;
        bool file_existed = VALID_STAT(fsp->fsp_name->st);
+       int curr_flags;
 
        *file_created = false;
 
@@ -652,59 +1069,65 @@ static NTSTATUS fd_open_atomic(struct connection_struct *conn,
         * we can never call O_CREAT without O_EXCL. So if
         * we think the file existed, try without O_CREAT|O_EXCL.
         * If we think the file didn't exist, try with
-        * O_CREAT|O_EXCL. Keep bouncing between these two
-        * requests until either the file is created, or
-        * opened. Either way, we keep going until we get
-        * a returnable result (error, or open/create).
+        * O_CREAT|O_EXCL.
+        *
+        * The big problem here is dangling symlinks. Opening
+        * without O_NOFOLLOW means both bad symlink
+        * and missing path return -1, ENOENT from open(). As POSIX
+        * is pathname based it's not possible to tell
+        * the difference between these two cases in a
+        * non-racy way, so change to try only two attempts before
+        * giving up.
+        *
+        * We don't have this problem for the O_NOFOLLOW
+        * case as it just returns NT_STATUS_OBJECT_PATH_NOT_FOUND
+        * mapped from the ELOOP POSIX error.
         */
 
-       while(1) {
-               int curr_flags = flags;
+       curr_flags = flags;
 
-               if (file_existed) {
-                       /* Just try open, do not create. */
-                       curr_flags &= ~(O_CREAT);
-                       status = fd_open(conn, fsp, curr_flags, mode);
-                       if (NT_STATUS_EQUAL(status,
-                                       NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-                               /*
-                                * Someone deleted it in the meantime.
-                                * Retry with O_EXCL.
-                                */
-                               file_existed = false;
-                               DEBUG(10,("fd_open_atomic: file %s existed. "
-                                       "Retry.\n",
-                                       smb_fname_str_dbg(fsp->fsp_name)));
-                                       continue;
-                       }
-               } else {
-                       /* Try create exclusively, fail if it exists. */
-                       curr_flags |= O_EXCL;
-                       status = fd_open(conn, fsp, curr_flags, mode);
-                       if (NT_STATUS_EQUAL(status,
-                                       NT_STATUS_OBJECT_NAME_COLLISION)) {
-                               /*
-                                * Someone created it in the meantime.
-                                * Retry without O_CREAT.
-                                */
-                               file_existed = true;
-                               DEBUG(10,("fd_open_atomic: file %s "
-                                       "did not exist. Retry.\n",
-                                       smb_fname_str_dbg(fsp->fsp_name)));
-                               continue;
-                       }
-                       if (NT_STATUS_IS_OK(status)) {
-                               /*
-                                * Here we've opened with O_CREAT|O_EXCL
-                                * and got success. We *know* we created
-                                * this file.
-                                */
-                               *file_created = true;
-                       }
+       if (file_existed) {
+               curr_flags &= ~(O_CREAT);
+               retry_status = NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       } else {
+               curr_flags |= O_EXCL;
+               retry_status = NT_STATUS_OBJECT_NAME_COLLISION;
+       }
+
+       status = fd_open(conn, fsp, curr_flags, mode);
+       if (NT_STATUS_IS_OK(status)) {
+               if (!file_existed) {
+                       *file_created = true;
                }
-               /* Create is done, or failed. */
-               break;
+               return NT_STATUS_OK;
+       }
+       if (!NT_STATUS_EQUAL(status, retry_status)) {
+               return status;
+       }
+
+       curr_flags = flags;
+
+       /*
+        * Keep file_existed up to date for clarity.
+        */
+       if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+               file_existed = false;
+               curr_flags |= O_EXCL;
+               DBG_DEBUG("file %s did not exist. Retry.\n",
+                       smb_fname_str_dbg(fsp->fsp_name));
+       } else {
+               file_existed = true;
+               curr_flags &= ~(O_CREAT);
+               DBG_DEBUG("file %s existed. Retry.\n",
+                       smb_fname_str_dbg(fsp->fsp_name));
        }
+
+       status = fd_open(conn, fsp, curr_flags, mode);
+
+       if (NT_STATUS_IS_OK(status) && (!file_existed)) {
+               *file_created = true;
+       }
+
        return status;
 }
 
@@ -718,8 +1141,8 @@ static NTSTATUS open_file(files_struct *fsp,
                          const char *parent_dir,
                          int flags,
                          mode_t unx_mode,
-                         uint32 access_mask, /* client requested access mask. */
-                         uint32 open_access_mask, /* what we're actually using in the open. */
+                         uint32_t access_mask, /* client requested access mask. */
+                         uint32_t open_access_mask, /* what we're actually using in the open. */
                          bool *p_file_created)
 {
        struct smb_filename *smb_fname = fsp->fsp_name;
@@ -808,6 +1231,7 @@ static NTSTATUS open_file(files_struct *fsp,
                        wild = smb_fname->base_name;
                }
                if ((local_flags & O_CREAT) && !file_existed &&
+                   !(fsp->posix_flags & FSP_POSIX_FLAGS_PATHNAMES) &&
                    ms_has_wild(wild))  {
                        return NT_STATUS_OBJECT_NAME_INVALID;
                }
@@ -881,6 +1305,25 @@ static NTSTATUS open_file(files_struct *fsp,
                        return status;
                }
 
+               if (local_flags & O_NONBLOCK) {
+                       /*
+                        * GPFS can return ETIMEDOUT for pread on
+                        * nonblocking file descriptors when files
+                        * migrated to tape need to be recalled. I
+                        * could imagine this happens elsehwere
+                        * too. With blocking file descriptors this
+                        * does not happen.
+                        */
+                       ret = set_blocking(fsp->fh->fd, true);
+                       if (ret == -1) {
+                               status = map_nt_error_from_unix(errno);
+                               DBG_WARNING("Could not set fd to blocking: "
+                                           "%s\n", strerror(errno));
+                               fd_close(fsp);
+                               return status;
+                       }
+               }
+
                ret = SMB_VFS_FSTAT(fsp, &smb_fname->st);
                if (ret == -1) {
                        /* If we have an fd, this stat should succeed. */
@@ -904,13 +1347,13 @@ static NTSTATUS open_file(files_struct *fsp,
                        /* Inherit the ACL if required */
                        if (lp_inherit_permissions(SNUM(conn))) {
                                inherit_access_posix_acl(conn, parent_dir,
-                                                        smb_fname->base_name,
+                                                        smb_fname,
                                                         unx_mode);
                                need_re_stat = true;
                        }
 
                        /* Change the owner if required. */
-                       if (lp_inherit_owner(SNUM(conn))) {
+                       if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO) {
                                change_file_owner_to_parent(conn, parent_dir,
                                                            fsp);
                                need_re_stat = true;
@@ -944,7 +1387,7 @@ static NTSTATUS open_file(files_struct *fsp,
                                access_mask);
 
                if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) &&
-                               fsp->posix_open &&
+                               (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) &&
                                S_ISLNK(smb_fname->st.st_ex_mode)) {
                        /* This is a POSIX stat open for delete
                         * or rename on a symlink that points
@@ -1013,8 +1456,8 @@ static NTSTATUS open_file(files_struct *fsp,
 ****************************************************************************/
 
 static bool share_conflict(struct share_mode_entry *entry,
-                          uint32 access_mask,
-                          uint32 share_access)
+                          uint32_t access_mask,
+                          uint32_t share_access)
 {
        DEBUG(10,("share_conflict: entry->access_mask = 0x%x, "
                  "entry->share_access = 0x%x, "
@@ -1101,6 +1544,7 @@ sa = 0x%x, share = 0x%x\n", (num), (unsigned int)(am), (unsigned int)(right), (u
 
 #if defined(DEVELOPER)
 static void validate_my_share_entries(struct smbd_server_connection *sconn,
+                                     const struct file_id id,
                                      int num,
                                      struct share_mode_entry *share_entry)
 {
@@ -1120,16 +1564,16 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
                return;
        }
 
-       fsp = file_find_dif(sconn, share_entry->id,
-                           share_entry->share_file_id);
+       fsp = file_find_dif(sconn, id, share_entry->share_file_id);
        if (!fsp) {
-               DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
-                        share_mode_str(talloc_tos(), num, share_entry) ));
+               DBG_ERR("PANIC : %s\n",
+                       share_mode_str(talloc_tos(), num, &id,
+                                      share_entry));
                smb_panic("validate_my_share_entries: Cannot match a "
                          "share entry with an open file\n");
        }
 
-       if (((uint16)fsp->oplock_type) != share_entry->op_type) {
+       if (((uint16_t)fsp->oplock_type) != share_entry->op_type) {
                goto panic;
        }
 
@@ -1138,8 +1582,9 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
  panic:
        {
                char *str;
-               DEBUG(0,("validate_my_share_entries: PANIC : %s\n",
-                        share_mode_str(talloc_tos(), num, share_entry) ));
+               DBG_ERR("validate_my_share_entries: PANIC : %s\n",
+                       share_mode_str(talloc_tos(), num, &id,
+                                      share_entry));
                str = talloc_asprintf(talloc_tos(),
                        "validate_my_share_entries: "
                        "file %s, oplock_type = 0x%x, op_type = 0x%x\n",
@@ -1151,7 +1596,7 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
 }
 #endif
 
-bool is_stat_open(uint32 access_mask)
+bool is_stat_open(uint32_t access_mask)
 {
        const uint32_t stat_open_bits =
                (SYNCHRONIZE_ACCESS|
@@ -1190,10 +1635,10 @@ static bool has_delete_on_close(struct share_mode_lock *lck,
 
 static NTSTATUS open_mode_check(connection_struct *conn,
                                struct share_mode_lock *lck,
-                               uint32 access_mask,
-                               uint32 share_access)
+                               uint32_t access_mask,
+                               uint32_t share_access)
 {
-       int i;
+       uint32_t i;
 
        if(lck->data->num_share_modes == 0) {
                return NT_STATUS_OK;
@@ -1211,7 +1656,7 @@ static NTSTATUS open_mode_check(connection_struct *conn,
 
 #if defined(DEVELOPER)
        for(i = 0; i < lck->data->num_share_modes; i++) {
-               validate_my_share_entries(conn->sconn, i,
+               validate_my_share_entries(conn->sconn, lck->data->id, i,
                                          &lck->data->share_modes[i]);
        }
 #endif
@@ -1244,29 +1689,31 @@ static NTSTATUS open_mode_check(connection_struct *conn,
  * our client.
  */
 
-static NTSTATUS send_break_message(struct messaging_context *msg_ctx,
-                                  const struct share_mode_entry *exclusive,
-                                  uint16_t break_to)
+NTSTATUS send_break_message(struct messaging_context *msg_ctx,
+                           const struct file_id *id,
+                           const struct share_mode_entry *exclusive,
+                           uint16_t break_to)
 {
        NTSTATUS status;
        char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+       struct server_id_buf tmp;
 
        DEBUG(10, ("Sending break request to PID %s\n",
-                  procid_str_static(&exclusive->pid)));
+                  server_id_str_buf(exclusive->pid, &tmp)));
 
        /* Create the message. */
-       share_mode_entry_to_message(msg, exclusive);
+       share_mode_entry_to_message(msg, id, exclusive);
 
        /* Overload entry->op_type */
        /*
-        * This is a cut from uint32 to uint16, but so far only the lower 3
+        * This is a cut from uint32_t to uint16_t, but so far only the lower 3
         * bits (LEASE_WRITE/HANDLE/READ are used anyway.
         */
        SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET, break_to);
 
        status = messaging_send_buf(msg_ctx, exclusive->pid,
                                    MSG_SMB_BREAK_REQUEST,
-                                   (uint8 *)msg, sizeof(msg));
+                                   (uint8_t *)msg, sizeof(msg));
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(3, ("Could not send oplock break message: %s\n",
                          nt_errstr(status)));
@@ -1431,7 +1878,7 @@ static bool delay_for_oplock(files_struct *fsp,
                        /*
                         * we'll decide about SMB2_LEASE_READ later.
                         *
-                        * Maybe the break will be defered
+                        * Maybe the break will be deferred
                         */
                        break_to &= ~SMB2_LEASE_HANDLE;
                }
@@ -1481,8 +1928,8 @@ static bool delay_for_oplock(files_struct *fsp,
 
                DEBUG(10, ("breaking from %d to %d\n",
                           (int)e_lease_type, (int)break_to));
-               send_break_message(fsp->conn->sconn->msg_ctx, e,
-                                  break_to);
+               send_break_message(fsp->conn->sconn->msg_ctx, &fsp->file_id,
+                                  e, break_to);
                if (e_lease_type & delay_mask) {
                        delay = true;
                }
@@ -1677,8 +2124,11 @@ static NTSTATUS grant_fsp_lease(struct files_struct *fsp,
                .epoch = fsp->lease->lease.lease_epoch,
        };
 
-       status = leases_db_add(client_guid, &lease->lease_key,
-                              &fsp->file_id, fsp->fsp_name->base_name,
+       status = leases_db_add(client_guid,
+                              &lease->lease_key,
+                              &fsp->file_id,
+                              fsp->conn->connectpath,
+                              fsp->fsp_name->base_name,
                               fsp->fsp_name->stream_name);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(10, ("%s: leases_db_add failed: %s\n", __func__,
@@ -1880,6 +2330,27 @@ static bool request_timed_out(struct timeval request_time,
        return (timeval_compare(&end_time, &now) < 0);
 }
 
+static struct deferred_open_record *deferred_open_record_create(
+       bool delayed_for_oplocks,
+       bool async_open,
+       struct file_id id)
+{
+       struct deferred_open_record *record = NULL;
+
+       record = talloc(NULL, struct deferred_open_record);
+       if (record == NULL) {
+               return NULL;
+       }
+
+       *record = (struct deferred_open_record) {
+               .delayed_for_oplocks = delayed_for_oplocks,
+               .async_open = async_open,
+               .id = id,
+       };
+
+       return record;
+}
+
 struct defer_open_state {
        struct smbXsrv_connection *xconn;
        uint64_t mid;
@@ -1887,64 +2358,72 @@ struct defer_open_state {
 
 static void defer_open_done(struct tevent_req *req);
 
-/****************************************************************************
- Handle the 1 second delay in returning a SHARING_VIOLATION error.
-****************************************************************************/
-
+/**
+ * Defer an open and watch a locking.tdb record
+ *
+ * This defers an open that gets rescheduled once the locking.tdb record watch
+ * is triggered by a change to the record.
+ *
+ * It is used to defer opens that triggered an oplock break and for the SMB1
+ * sharing violation delay.
+ **/
 static void defer_open(struct share_mode_lock *lck,
                       struct timeval request_time,
                       struct timeval timeout,
                       struct smb_request *req,
-                      struct deferred_open_record *state)
+                      bool delayed_for_oplocks,
+                      struct file_id id)
 {
-       struct deferred_open_record *open_rec;
+       struct deferred_open_record *open_rec = NULL;
+       struct timeval abs_timeout;
+       struct defer_open_state *watch_state;
+       struct tevent_req *watch_req;
+       bool ok;
+
+       abs_timeout = timeval_sum(&request_time, &timeout);
 
-       DEBUG(10,("defer_open_sharing_error: time [%u.%06u] adding deferred "
-                 "open entry for mid %llu\n",
-                 (unsigned int)request_time.tv_sec,
-                 (unsigned int)request_time.tv_usec,
-                 (unsigned long long)req->mid));
+       DBG_DEBUG("request time [%s] timeout [%s] mid [%" PRIu64 "] "
+                 "delayed_for_oplocks [%s] file_id [%s]\n",
+                 timeval_string(talloc_tos(), &request_time, false),
+                 timeval_string(talloc_tos(), &abs_timeout, false),
+                 req->mid,
+                 delayed_for_oplocks ? "yes" : "no",
+                 file_id_string_tos(&id));
 
-       open_rec = talloc(NULL, struct deferred_open_record);
+       open_rec = deferred_open_record_create(delayed_for_oplocks,
+                                              false,
+                                              id);
        if (open_rec == NULL) {
                TALLOC_FREE(lck);
                exit_server("talloc failed");
        }
 
-       *open_rec = *state;
-
-       if (lck) {
-               struct defer_open_state *watch_state;
-               struct tevent_req *watch_req;
-               bool ret;
-
-               watch_state = talloc(open_rec, struct defer_open_state);
-               if (watch_state == NULL) {
-                       exit_server("talloc failed");
-               }
-               watch_state->xconn = req->xconn;
-               watch_state->mid = req->mid;
+       watch_state = talloc(open_rec, struct defer_open_state);
+       if (watch_state == NULL) {
+               exit_server("talloc failed");
+       }
+       watch_state->xconn = req->xconn;
+       watch_state->mid = req->mid;
 
-               DEBUG(10, ("defering mid %llu\n",
-                          (unsigned long long)req->mid));
+       DBG_DEBUG("defering mid %" PRIu64 "\n", req->mid);
 
-               watch_req = dbwrap_record_watch_send(
-                       watch_state, req->sconn->ev_ctx, lck->data->record,
-                       req->sconn->msg_ctx);
-               if (watch_req == NULL) {
-                       exit_server("Could not watch share mode record");
-               }
-               tevent_req_set_callback(watch_req, defer_open_done,
-                                       watch_state);
+       watch_req = dbwrap_watched_watch_send(watch_state,
+                                             req->sconn->ev_ctx,
+                                             lck->data->record,
+                                             (struct server_id){0});
+       if (watch_req == NULL) {
+               exit_server("Could not watch share mode record");
+       }
+       tevent_req_set_callback(watch_req, defer_open_done, watch_state);
 
-               ret = tevent_req_set_endtime(
-                       watch_req, req->sconn->ev_ctx,
-                       timeval_sum(&request_time, &timeout));
-               SMB_ASSERT(ret);
+       ok = tevent_req_set_endtime(watch_req, req->sconn->ev_ctx, abs_timeout);
+       if (!ok) {
+               exit_server("tevent_req_set_endtime failed");
        }
 
-       if (!push_deferred_open_message_smb(req, request_time, timeout,
-                                           state->id, open_rec)) {
+       ok = push_deferred_open_message_smb(req, request_time, timeout,
+                                           open_rec->id, open_rec);
+       if (!ok) {
                TALLOC_FREE(lck);
                exit_server("push_deferred_open_message_smb failed");
        }
@@ -1957,10 +2436,10 @@ static void defer_open_done(struct tevent_req *req)
        NTSTATUS status;
        bool ret;
 
-       status = dbwrap_record_watch_recv(req, talloc_tos(), NULL);
+       status = dbwrap_watched_watch_recv(req, NULL, NULL);
        TALLOC_FREE(req);
        if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(5, ("dbwrap_record_watch_recv returned %s\n",
+               DEBUG(5, ("dbwrap_watched_watch_recv returned %s\n",
                          nt_errstr(status)));
                /*
                 * Even if it failed, retry anyway. TODO: We need a way to
@@ -1975,19 +2454,87 @@ static void defer_open_done(struct tevent_req *req)
        TALLOC_FREE(state);
 }
 
+/**
+ * Actually attempt the kernel oplock polling open.
+ */
+
+static void kernel_oplock_poll_open_timer(struct tevent_context *ev,
+                                     struct tevent_timer *te,
+                                     struct timeval current_time,
+                                     void *private_data)
+{
+       bool ok;
+       struct smb_request *req = (struct smb_request *)private_data;
+
+       ok = schedule_deferred_open_message_smb(req->xconn, req->mid);
+       if (!ok) {
+               exit_server("schedule_deferred_open_message_smb failed");
+       }
+       DBG_DEBUG("kernel_oplock_poll_open_timer fired. Retying open !\n");
+}
+
+/**
+ * Reschedule an open for 1 second from now, if not timed out.
+ **/
+static void setup_kernel_oplock_poll_open(struct timeval request_time,
+                      struct smb_request *req,
+                      struct file_id id)
+{
+
+       bool ok;
+       struct deferred_open_record *open_rec = NULL;
+       /* Maximum wait time. */
+       struct timeval timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
+
+       if (request_timed_out(request_time, timeout)) {
+               return;
+       }
+
+       open_rec = deferred_open_record_create(false, false, id);
+       if (open_rec == NULL) {
+               exit_server("talloc failed");
+       }
+
+       ok = push_deferred_open_message_smb(req,
+                                           request_time,
+                                           timeout,
+                                           id,
+                                           open_rec);
+       if (!ok) {
+               exit_server("push_deferred_open_message_smb failed");
+       }
+
+       /*
+        * As this timer event is owned by req, it will
+        * disappear if req it talloc_freed.
+        */
+       open_rec->te = tevent_add_timer(req->sconn->ev_ctx,
+                                       req,
+                                       timeval_current_ofs(1, 0),
+                                       kernel_oplock_poll_open_timer,
+                                       req);
+       if (open_rec->te == NULL) {
+               exit_server("tevent_add_timer failed");
+       }
+
+       DBG_DEBUG("poll request time [%s] mid [%" PRIu64 "] file_id [%s]\n",
+                 timeval_string(talloc_tos(), &request_time, false),
+                 req->mid,
+                 file_id_string_tos(&id));
+}
 
 /****************************************************************************
  On overwrite open ensure that the attributes match.
 ****************************************************************************/
 
 static bool open_match_attributes(connection_struct *conn,
-                                 uint32 old_dos_attr,
-                                 uint32 new_dos_attr,
+                                 uint32_t old_dos_attr,
+                                 uint32_t new_dos_attr,
                                  mode_t existing_unx_mode,
                                  mode_t new_unx_mode,
                                  mode_t *returned_unx_mode)
 {
-       uint32 noarch_old_dos_attr, noarch_new_dos_attr;
+       uint32_t noarch_old_dos_attr, noarch_new_dos_attr;
 
        noarch_old_dos_attr = (old_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
        noarch_new_dos_attr = (new_dos_attr & ~FILE_ATTRIBUTE_ARCHIVE);
@@ -2033,11 +2580,11 @@ static NTSTATUS fcb_or_dos_open(struct smb_request *req,
                                files_struct *fsp_to_dup_into,
                                const struct smb_filename *smb_fname,
                                struct file_id id,
-                               uint16 file_pid,
+                               uint16_t file_pid,
                                uint64_t vuid,
-                               uint32 access_mask,
-                               uint32 share_access,
-                               uint32 create_options)
+                               uint32_t access_mask,
+                               uint32_t share_access,
+                               uint32_t create_options)
 {
        files_struct *fsp;
 
@@ -2091,8 +2638,6 @@ static void schedule_defer_open(struct share_mode_lock *lck,
                                struct timeval request_time,
                                struct smb_request *req)
 {
-       struct deferred_open_record state;
-
        /* This is a relative time, added to the absolute
           request_time value to get the absolute timeout time.
           Note that if this is the second or greater time we enter
@@ -2111,38 +2656,54 @@ static void schedule_defer_open(struct share_mode_lock *lck,
 
        timeout = timeval_set(OPLOCK_BREAK_TIMEOUT*2, 0);
 
-       /* Nothing actually uses state.delayed_for_oplocks
-          but it's handy to differentiate in debug messages
-          between a 30 second delay due to oplock break, and
-          a 1 second delay for share mode conflicts. */
-
-       state.delayed_for_oplocks = True;
-       state.async_open = false;
-       state.id = id;
-
-       if (!request_timed_out(request_time, timeout)) {
-               defer_open(lck, request_time, timeout, req, &state);
+       if (request_timed_out(request_time, timeout)) {
+               return;
        }
+
+       defer_open(lck, request_time, timeout, req, true, id);
 }
 
 /****************************************************************************
  Reschedule an open call that went asynchronous.
 ****************************************************************************/
 
+static void schedule_async_open_timer(struct tevent_context *ev,
+                                     struct tevent_timer *te,
+                                     struct timeval current_time,
+                                     void *private_data)
+{
+       exit_server("async open timeout");
+}
+
 static void schedule_async_open(struct timeval request_time,
                                struct smb_request *req)
 {
-       struct deferred_open_record state;
-       struct timeval timeout;
+       struct deferred_open_record *open_rec = NULL;
+       struct timeval timeout = timeval_set(20, 0);
+       bool ok;
 
-       timeout = timeval_set(20, 0);
+       if (request_timed_out(request_time, timeout)) {
+               return;
+       }
 
-       ZERO_STRUCT(state);
-       state.delayed_for_oplocks = false;
-       state.async_open = true;
+       open_rec = deferred_open_record_create(false, true, (struct file_id){0});
+       if (open_rec == NULL) {
+               exit_server("deferred_open_record_create failed");
+       }
 
-       if (!request_timed_out(request_time, timeout)) {
-               defer_open(NULL, request_time, timeout, req, &state);
+       ok = push_deferred_open_message_smb(req, request_time, timeout,
+                                           (struct file_id){0}, open_rec);
+       if (!ok) {
+               exit_server("push_deferred_open_message_smb failed");
+       }
+
+       open_rec->te = tevent_add_timer(req->sconn->ev_ctx,
+                                       req,
+                                       timeval_current_ofs(20, 0),
+                                       schedule_async_open_timer,
+                                       open_rec);
+       if (open_rec->te == NULL) {
+               exit_server("tevent_add_timer failed");
        }
 }
 
@@ -2165,7 +2726,7 @@ static NTSTATUS smbd_calculate_maximum_allowed_access(
                return NT_STATUS_OK;
        }
 
-       status = SMB_VFS_GET_NT_ACL(conn, smb_fname->base_name,
+       status = SMB_VFS_GET_NT_ACL(conn, smb_fname,
                                    (SECINFO_OWNER |
                                     SECINFO_GROUP |
                                     SECINFO_DACL),
@@ -2230,6 +2791,12 @@ NTSTATUS smbd_calculate_access_mask(connection_struct *conn,
        uint32_t orig_access_mask = access_mask;
        uint32_t rejected_share_access;
 
+       if (access_mask & SEC_MASK_INVALID) {
+               DBG_DEBUG("access_mask [%8x] contains invalid bits\n",
+                         access_mask);
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
        /*
         * Convert GENERIC bits to specific bits.
         */
@@ -2349,7 +2916,6 @@ static int disposition_to_open_flags(uint32_t create_disposition)
 }
 
 static int calculate_open_access_flags(uint32_t access_mask,
-                                      int oplock_request,
                                       uint32_t private_flags)
 {
        bool need_write, need_read;
@@ -2385,11 +2951,11 @@ static int calculate_open_access_flags(uint32_t access_mask,
 
 static NTSTATUS open_file_ntcreate(connection_struct *conn,
                            struct smb_request *req,
-                           uint32 access_mask,         /* access bits (FILE_READ_DATA etc.) */
-                           uint32 share_access,        /* share constants (FILE_SHARE_READ etc) */
-                           uint32 create_disposition,  /* FILE_OPEN_IF etc. */
-                           uint32 create_options,      /* options such as delete on close. */
-                           uint32 new_dos_attributes,  /* attributes used for new file. */
+                           uint32_t access_mask,               /* access bits (FILE_READ_DATA etc.) */
+                           uint32_t share_access,      /* share constants (FILE_SHARE_READ etc) */
+                           uint32_t create_disposition,        /* FILE_OPEN_IF etc. */
+                           uint32_t create_options,    /* options such as delete on close. */
+                           uint32_t new_dos_attributes,        /* attributes used for new file. */
                            int oplock_request,         /* internal Samba oplock codes. */
                            struct smb2_lease *lease,
                                                        /* Information (FILE_EXISTS etc.) */
@@ -2409,10 +2975,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        mode_t new_unx_mode = (mode_t)0;
        mode_t unx_mode = (mode_t)0;
        int info;
-       uint32 existing_dos_attributes = 0;
+       uint32_t existing_dos_attributes = 0;
        struct timeval request_time = timeval_zero();
        struct share_mode_lock *lck = NULL;
-       uint32 open_access_mask = access_mask;
+       uint32_t open_access_mask = access_mask;
        NTSTATUS status;
        char *parent_dir;
        SMB_STRUCT_STAT saved_stat = smb_fname->st;
@@ -2512,7 +3078,18 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        if (!posix_open) {
                new_dos_attributes &= SAMBA_ATTRIBUTES_MASK;
                if (file_existed) {
-                       existing_dos_attributes = dos_mode(conn, smb_fname);
+                       /*
+                        * Only use strored DOS attributes for checks
+                        * against requested attributes (below via
+                        * open_match_attributes()), cf bug #11992
+                        * for details. -slow
+                        */
+                       uint32_t attr = 0;
+
+                       status = SMB_VFS_GET_DOS_ATTRIBUTES(conn, smb_fname, &attr);
+                       if (NT_STATUS_IS_OK(status)) {
+                               existing_dos_attributes = attr;
+                       }
                }
        }
 
@@ -2524,7 +3101,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        /* this is for OS/2 long file names - say we don't support them */
-       if (!lp_posix_pathnames() && strstr(smb_fname->base_name,".+,;=[].")) {
+       if (req != NULL && !req->posix_pathnames &&
+                       strstr(smb_fname->base_name,".+,;=[].")) {
                /* OS/2 Workplace shell fix may be main code stream in a later
                 * release. */
                DEBUG(5,("open_file_ntcreate: OS/2 long filenames are not "
@@ -2636,8 +3214,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
         * mean the same thing under DOS and Unix.
         */
 
-       flags = calculate_open_access_flags(access_mask, oplock_request,
-                                           private_flags);
+       flags = calculate_open_access_flags(access_mask, private_flags);
 
        /*
         * Currently we only look at FILE_WRITE_THROUGH for create options.
@@ -2662,20 +3239,18 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                flags2 &= ~(O_CREAT|O_TRUNC);
        }
 
-       if (first_open_attempt && lp_kernel_oplocks(SNUM(conn))) {
+       if (lp_kernel_oplocks(SNUM(conn))) {
                /*
                 * With kernel oplocks the open breaking an oplock
                 * blocks until the oplock holder has given up the
-                * oplock or closed the file. We prevent this by first
+                * oplock or closed the file. We prevent this by always
                 * trying to open the file with O_NONBLOCK (see "man
-                * fcntl" on Linux). For the second try, triggered by
-                * an oplock break response, we do not need this
-                * anymore.
+                * fcntl" on Linux).
                 *
-                * This is true under the assumption that only Samba
-                * requests kernel oplocks. Once someone else like
-                * NFSv4 starts to use that API, we will have to
-                * modify this by communicating with the NFSv4 server.
+                * If a process that doesn't use the smbd open files
+                * database or communication methods holds a kernel
+                * oplock we must periodically poll for available open
+                * using O_NONBLOCK.
                 */
                flags2 |= O_NONBLOCK;
        }
@@ -2700,7 +3275,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        fsp->access_mask = open_access_mask; /* We change this to the
                                              * requested access_mask after
                                              * the open is done. */
-       fsp->posix_open = posix_open;
+       if (posix_open) {
+               fsp->posix_flags |= FSP_POSIX_FLAGS_ALL;
+       }
 
        if (timeval_is_zero(&request_time)) {
                request_time = fsp->open_time;
@@ -2726,10 +3303,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                             open_access_mask, &new_file_created);
 
        if (NT_STATUS_EQUAL(fsp_open, NT_STATUS_NETWORK_BUSY)) {
-               struct deferred_open_record state;
+               bool delay;
 
                /*
-                * EWOULDBLOCK/EAGAIN maps to NETWORK_BUSY.
+                * This handles the kernel oplock case:
+                *
+                * the file has an active kernel oplock and the open() returned
+                * EWOULDBLOCK/EAGAIN which maps to NETWORK_BUSY.
+                *
+                * "Samba locking.tdb oplocks" are handled below after acquiring
+                * the sharemode lock with get_share_mode_lock().
                 */
                if (file_existed && S_ISFIFO(fsp->fsp_name->st.st_ex_mode)) {
                        DEBUG(10, ("FIFO busy\n"));
@@ -2746,13 +3329,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
                if (lck == NULL) {
-                       state.delayed_for_oplocks = false;
-                       state.async_open = false;
-                       state.id = fsp->file_id;
-                       defer_open(NULL, request_time, timeval_set(0, 0),
-                                  req, &state);
-                       DEBUG(10, ("No share mode lock found after "
-                                  "EWOULDBLOCK, retrying sync\n"));
+                       /*
+                        * No oplock from Samba around. Set up a poll every 1
+                        * second to retry a non-blocking open until the time
+                        * expires.
+                        */
+                       setup_kernel_oplock_poll_open(request_time,
+                                               req,
+                                               fsp->file_id);
+                       DBG_DEBUG("No Samba oplock around after EWOULDBLOCK. "
+                               "Retrying with poll\n");
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
@@ -2760,8 +3346,10 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                        smb_panic("validate_oplock_types failed");
                }
 
-               if (delay_for_oplock(fsp, 0, lease, lck, false,
-                                    create_disposition, first_open_attempt)) {
+               delay = delay_for_oplock(fsp, 0, lease, lck, false,
+                                        create_disposition,
+                                        first_open_attempt);
+               if (delay) {
                        schedule_defer_open(lck, fsp->file_id, request_time,
                                            req);
                        TALLOC_FREE(lck);
@@ -2771,16 +3359,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
 
                /*
-                * No oplock from Samba around. Immediately retry with
-                * a blocking open.
+                * No oplock from Samba around. Set up a poll every 1
+                * second to retry a non-blocking open until the time
+                * expires.
                 */
-               state.delayed_for_oplocks = false;
-               state.async_open = false;
-               state.id = fsp->file_id;
-               defer_open(lck, request_time, timeval_set(0, 0), req, &state);
+               setup_kernel_oplock_poll_open(request_time, req, fsp->file_id);
+
                TALLOC_FREE(lck);
-               DEBUG(10, ("No Samba oplock around after EWOULDBLOCK. "
-                          "Retrying sync\n"));
+               DBG_DEBUG("No Samba oplock around after EWOULDBLOCK. "
+                       "Retrying with poll\n");
                return NT_STATUS_SHARING_VIOLATION;
        }
 
@@ -2882,19 +3469,31 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                file_existed = true;
        }
 
-       if ((req != NULL) &&
-           delay_for_oplock(
-                   fsp, oplock_request, lease, lck,
-                   NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION),
-                   create_disposition, first_open_attempt)) {
-               schedule_defer_open(lck, fsp->file_id, request_time, req);
-               TALLOC_FREE(lck);
-               fd_close(fsp);
-               return NT_STATUS_SHARING_VIOLATION;
+       if (req != NULL) {
+               /*
+                * Handle oplocks, deferring the request if delay_for_oplock()
+                * triggered a break message and we have to wait for the break
+                * response.
+                */
+               bool delay;
+               bool sharing_violation = NT_STATUS_EQUAL(
+                       status, NT_STATUS_SHARING_VIOLATION);
+
+               delay = delay_for_oplock(fsp, oplock_request, lease, lck,
+                                        sharing_violation,
+                                        create_disposition,
+                                        first_open_attempt);
+               if (delay) {
+                       schedule_defer_open(lck, fsp->file_id,
+                                           request_time, req);
+                       TALLOC_FREE(lck);
+                       fd_close(fsp);
+                       return NT_STATUS_SHARING_VIOLATION;
+               }
        }
 
        if (!NT_STATUS_IS_OK(status)) {
-               uint32 can_access_mask;
+               uint32_t can_access_mask;
                bool can_access = True;
 
                SMB_ASSERT(NT_STATUS_EQUAL(status, NT_STATUS_SHARING_VIOLATION));
@@ -2970,7 +3569,6 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                    !conn->sconn->using_smb2 &&
                    lp_defer_sharing_violations()) {
                        struct timeval timeout;
-                       struct deferred_open_record state;
                        int timeout_usecs;
 
                        /* this is a hack to speed up torture tests
@@ -2989,20 +3587,9 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        timeout = timeval_set(0, timeout_usecs);
 
-                       /* Nothing actually uses state.delayed_for_oplocks
-                          but it's handy to differentiate in debug messages
-                          between a 30 second delay due to oplock break, and
-                          a 1 second delay for share mode conflicts. */
-
-                       state.delayed_for_oplocks = False;
-                       state.async_open = false;
-                       state.id = id;
-
-                       if ((req != NULL)
-                           && !request_timed_out(request_time,
-                                                 timeout)) {
-                               defer_open(lck, request_time, timeout,
-                                          req, &state);
+                       if (!request_timed_out(request_time, timeout)) {
+                               defer_open(lck, request_time, timeout, req,
+                                          false, id);
                        }
                }
 
@@ -3042,7 +3629,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        /* Delete streams if create_disposition requires it */
        if (!new_file_created && clear_ads(create_disposition) &&
            !is_ntfs_stream_smb_fname(smb_fname)) {
-               status = delete_all_streams(conn, smb_fname->base_name);
+               status = delete_all_streams(conn, smb_fname);
                if (!NT_STATUS_IS_OK(status)) {
                        TALLOC_FREE(lck);
                        fd_close(fsp);
@@ -3060,6 +3647,15 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
        if (fsp->fh->fd != -1 && lp_kernel_share_modes(SNUM(conn))) {
                int ret_flock;
+               /*
+                * Beware: streams implementing VFS modules may
+                * implement streams in a way that fsp will have the
+                * basefile open in the fsp fd, so lacking a distinct
+                * fd for the stream kernel_flock will apply on the
+                * basefile which is wrong. The actual check is
+                * deffered to the VFS module implementing the
+                * kernel_flock call.
+                */
                ret_flock = SMB_VFS_KERNEL_FLOCK(fsp, share_access, access_mask);
                if(ret_flock == -1 ){
 
@@ -3068,6 +3664,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        return NT_STATUS_SHARING_VIOLATION;
                }
+
+               fsp->kernel_share_modes_taken = true;
        }
 
        /*
@@ -3095,7 +3693,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
        if (file_existed) {
                /*
-                * stat opens on existing files don't get oplocks or leases.
+                * stat opens on existing files don't get oplocks.
+                * They can get leases.
                 *
                 * Note that we check for stat open on the *open_access_mask*,
                 * i.e. the access mask we actually used to do the open,
@@ -3104,12 +3703,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
                 * FILE_OVERWRITE and FILE_OVERWRITE_IF add in O_TRUNC,
                 * which adds FILE_WRITE_DATA to open_access_mask.
                 */
-               if (is_stat_open(open_access_mask)) {
-                       if (lease) {
-                               lease->lease_state = SMB2_LEASE_NONE;
-                       } else {
-                               oplock_request = NO_OPLOCK;
-                       }
+               if (is_stat_open(open_access_mask) && lease == NULL) {
+                       oplock_request = NO_OPLOCK;
                }
        }
 
@@ -3156,8 +3751,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        if (info != FILE_WAS_OPENED) {
-               /* Files should be initially set as archive */
-               if (lp_map_archive(SNUM(conn)) ||
+               /* Overwritten files should be initially set as archive */
+               if ((info == FILE_WAS_OVERWRITTEN && lp_map_archive(SNUM(conn))) ||
                    lp_store_dos_attributes(SNUM(conn))) {
                        if (!posix_open) {
                                if (file_set_dosmode(conn, smb_fname,
@@ -3241,7 +3836,7 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
 static NTSTATUS mkdir_internal(connection_struct *conn,
                               struct smb_filename *smb_dname,
-                              uint32 file_attributes)
+                              uint32_t file_attributes)
 {
        mode_t mode;
        char *parent_dir = NULL;
@@ -3280,7 +3875,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                return status;
        }
 
-       if (SMB_VFS_MKDIR(conn, smb_dname->base_name, mode) != 0) {
+       if (SMB_VFS_MKDIR(conn, smb_dname, mode) != 0) {
                return map_nt_error_from_unix(errno);
        }
 
@@ -3309,7 +3904,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
 
        if (lp_inherit_permissions(SNUM(conn))) {
                inherit_access_posix_acl(conn, parent_dir,
-                                        smb_dname->base_name, mode);
+                                        smb_dname, mode);
                need_re_stat = true;
        }
 
@@ -3322,7 +3917,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
                 */
                if ((mode & ~(S_IRWXU|S_IRWXG|S_IRWXO)) &&
                    (mode & ~smb_dname->st.st_ex_mode)) {
-                       SMB_VFS_CHMOD(conn, smb_dname->base_name,
+                       SMB_VFS_CHMOD(conn, smb_dname,
                                      (smb_dname->st.st_ex_mode |
                                          (mode & ~smb_dname->st.st_ex_mode)));
                        need_re_stat = true;
@@ -3330,9 +3925,9 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
        }
 
        /* Change the owner if required. */
-       if (lp_inherit_owner(SNUM(conn))) {
+       if (lp_inherit_owner(SNUM(conn)) != INHERIT_OWNER_NO) {
                change_dir_owner_to_parent(conn, parent_dir,
-                                          smb_dname->base_name,
+                                          smb_dname,
                                           &smb_dname->st);
                need_re_stat = true;
        }
@@ -3358,11 +3953,11 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
 static NTSTATUS open_directory(connection_struct *conn,
                               struct smb_request *req,
                               struct smb_filename *smb_dname,
-                              uint32 access_mask,
-                              uint32 share_access,
-                              uint32 create_disposition,
-                              uint32 create_options,
-                              uint32 file_attributes,
+                              uint32_t access_mask,
+                              uint32_t share_access,
+                              uint32_t create_disposition,
+                              uint32_t create_options,
+                              uint32_t file_attributes,
                               int *pinfo,
                               files_struct **result)
 {
@@ -3477,6 +4072,25 @@ static NTSTATUS open_directory(connection_struct *conn,
                                                        nt_errstr(status)));
                                                return status;
                                        }
+
+                                       /*
+                                        * If mkdir_internal() returned
+                                        * NT_STATUS_OBJECT_NAME_COLLISION
+                                        * we still must lstat the path.
+                                        */
+
+                                       if (SMB_VFS_LSTAT(conn, smb_dname)
+                                                       == -1) {
+                                               DEBUG(2, ("Could not stat "
+                                                       "directory '%s' just "
+                                                       "opened: %s\n",
+                                                       smb_fname_str_dbg(
+                                                               smb_dname),
+                                                       strerror(errno)));
+                                               return map_nt_error_from_unix(
+                                                               errno);
+                                       }
+
                                        info = FILE_WAS_OPENED;
                                }
                        }
@@ -3541,7 +4155,9 @@ static NTSTATUS open_directory(connection_struct *conn,
        fsp->oplock_type = NO_OPLOCK;
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = True;
-       fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False;
+       if (file_attributes & FILE_FLAG_POSIX_SEMANTICS) {
+               fsp->posix_flags |= FSP_POSIX_FLAGS_ALL;
+       }
        status = fsp_set_smb_fname(fsp, smb_dname);
        if (!NT_STATUS_IS_OK(status)) {
                file_free(req, fsp);
@@ -3590,8 +4206,18 @@ static NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
-       /* Ensure there was no race condition. */
-       if (!check_same_stat(&smb_dname->st, &fsp->fsp_name->st)) {
+       if(!S_ISDIR(fsp->fsp_name->st.st_ex_mode)) {
+               DEBUG(5,("open_directory: %s is not a directory !\n",
+                        smb_fname_str_dbg(smb_dname)));
+                fd_close(fsp);
+                file_free(req, fsp);
+               return NT_STATUS_NOT_A_DIRECTORY;
+       }
+
+       /* Ensure there was no race condition.  We need to check
+        * dev/inode but not permissions, as these can change
+        * legitimately */
+       if (!check_same_dev_ino(&smb_dname->st, &fsp->fsp_name->st)) {
                DEBUG(5,("open_directory: stat struct differs for "
                        "directory %s.\n",
                        smb_fname_str_dbg(smb_dname)));
@@ -3703,7 +4329,8 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req,
                NULL,                                   /* sd */
                NULL,                                   /* ea_list */
                &fsp,                                   /* result */
-               NULL);                                  /* pinfo */
+               NULL,                                   /* pinfo */
+               NULL, NULL);                            /* create context */
 
        if (NT_STATUS_IS_OK(status)) {
                close_file(req, fsp, NORMAL_CLOSE);
@@ -3756,8 +4383,11 @@ void msg_file_was_renamed(struct messaging_context *msg,
                stream_name = NULL;
        }
 
-       smb_fname = synthetic_smb_fname(talloc_tos(), base_name,
-                                       stream_name, NULL);
+       smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       base_name,
+                                       stream_name,
+                                       NULL,
+                                       0);
        if (smb_fname == NULL) {
                return;
        }
@@ -3803,8 +4433,8 @@ void msg_file_was_renamed(struct messaging_context *msg,
  * If that works, delete them all by setting the delete on close and close.
  */
 
-NTSTATUS open_streams_for_delete(connection_struct *conn,
-                                       const char *fname)
+static NTSTATUS open_streams_for_delete(connection_struct *conn,
+                                       const struct smb_filename *smb_fname)
 {
        struct stream_struct *stream_info = NULL;
        files_struct **streams = NULL;
@@ -3813,7 +4443,7 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
        TALLOC_CTX *frame = talloc_stackframe();
        NTSTATUS status;
 
-       status = vfs_streaminfo(conn, NULL, fname, talloc_tos(),
+       status = vfs_streaminfo(conn, NULL, smb_fname, talloc_tos(),
                                &num_streams, &stream_info);
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_IMPLEMENTED)
@@ -3845,30 +4475,34 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
        }
 
        for (i=0; i<num_streams; i++) {
-               struct smb_filename *smb_fname;
+               struct smb_filename *smb_fname_cp;
 
                if (strequal(stream_info[i].name, "::$DATA")) {
                        streams[i] = NULL;
                        continue;
                }
 
-               smb_fname = synthetic_smb_fname(
-                       talloc_tos(), fname, stream_info[i].name, NULL);
-               if (smb_fname == NULL) {
+               smb_fname_cp = synthetic_smb_fname(talloc_tos(),
+                                       smb_fname->base_name,
+                                       stream_info[i].name,
+                                       NULL,
+                                       (smb_fname->flags &
+                                               ~SMB_FILENAME_POSIX_PATH));
+               if (smb_fname_cp == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto fail;
                }
 
-               if (SMB_VFS_STAT(conn, smb_fname) == -1) {
+               if (SMB_VFS_STAT(conn, smb_fname_cp) == -1) {
                        DEBUG(10, ("Unable to stat stream: %s\n",
-                                  smb_fname_str_dbg(smb_fname)));
+                                  smb_fname_str_dbg(smb_fname_cp)));
                }
 
                status = SMB_VFS_CREATE_FILE(
                         conn,                  /* conn */
                         NULL,                  /* req */
                         0,                     /* root_dir_fid */
-                        smb_fname,             /* fname */
+                        smb_fname_cp,          /* fname */
                         DELETE_ACCESS,         /* access_mask */
                         (FILE_SHARE_READ |     /* share_access */
                             FILE_SHARE_WRITE | FILE_SHARE_DELETE),
@@ -3882,17 +4516,18 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
                         NULL,                  /* sd */
                         NULL,                  /* ea_list */
                         &streams[i],           /* result */
-                        NULL);                 /* pinfo */
+                        NULL,                  /* pinfo */
+                        NULL, NULL);           /* create context */
 
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(10, ("Could not open stream %s: %s\n",
-                                  smb_fname_str_dbg(smb_fname),
+                                  smb_fname_str_dbg(smb_fname_cp),
                                   nt_errstr(status)));
 
-                       TALLOC_FREE(smb_fname);
+                       TALLOC_FREE(smb_fname_cp);
                        break;
                }
-               TALLOC_FREE(smb_fname);
+               TALLOC_FREE(smb_fname_cp);
        }
 
        /*
@@ -3932,7 +4567,8 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
        const struct dom_sid *group_sid = NULL;
        uint32_t security_info_sent = (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL);
        struct security_token *token = fsp->conn->session_info->security_token;
-       bool inherit_owner = lp_inherit_owner(SNUM(fsp->conn));
+       bool inherit_owner =
+           (lp_inherit_owner(SNUM(fsp->conn)) == INHERIT_OWNER_WINDOWS_AND_UNIX);
        bool inheritable_components = false;
        bool try_builtin_administrators = false;
        const struct dom_sid *BA_U_sid = NULL;
@@ -3941,14 +4577,25 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
        const struct dom_sid *SY_U_sid = NULL;
        const struct dom_sid *SY_G_sid = NULL;
        size_t size = 0;
+       struct smb_filename *parent_smb_fname = NULL;
 
        if (!parent_dirname(frame, fsp->fsp_name->base_name, &parent_name, NULL)) {
                TALLOC_FREE(frame);
                return NT_STATUS_NO_MEMORY;
        }
+       parent_smb_fname = synthetic_smb_fname(talloc_tos(),
+                                               parent_name,
+                                               NULL,
+                                               NULL,
+                                               fsp->fsp_name->flags);
+
+       if (parent_smb_fname == NULL) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
 
        status = SMB_VFS_GET_NT_ACL(fsp->conn,
-                                   parent_name,
+                                   parent_smb_fname,
                                    (SECINFO_OWNER | SECINFO_GROUP | SECINFO_DACL),
                                    frame,
                                    &parent_desc);
@@ -4122,8 +4769,10 @@ static NTSTATUS inherit_new_acl(files_struct *fsp)
  * used for a different file name.
  */
 
-struct lease_fname_match_state {
+struct lease_match_state {
        /* Input parameters. */
+       TALLOC_CTX *mem_ctx;
+       const char *servicepath;
        const struct smb_filename *fname;
        bool file_existed;
        struct file_id id;
@@ -4133,57 +4782,139 @@ struct lease_fname_match_state {
        NTSTATUS match_status;
 };
 
-static void lease_fname_match_parser(
-       uint32_t num_file_ids,
-       struct file_id *ids, const char *filename, const char *stream_name,
+/*************************************************************
+ File doesn't exist but this lease key+guid is already in use.
+
+ This is only allowable in the dynamic share case where the
+ service path must be different.
+
+ There is a small race condition here in the multi-connection
+ case where a client sends two create calls on different connections,
+ where the file doesn't exist and one smbd creates the leases_db
+ entry first, but this will get fixed by the multichannel cleanup
+ when all identical client_guids get handled by a single smbd.
+**************************************************************/
+
+static void lease_match_parser_new_file(
+       uint32_t num_files,
+       const struct leases_db_file *files,
+       struct lease_match_state *state)
+{
+       uint32_t i;
+
+       for (i = 0; i < num_files; i++) {
+               const struct leases_db_file *f = &files[i];
+               if (strequal(state->servicepath, f->servicepath)) {
+                       state->match_status = NT_STATUS_INVALID_PARAMETER;
+                       return;
+               }
+       }
+
+       /* Dynamic share case. Break leases on all other files. */
+       state->match_status = leases_db_copy_file_ids(state->mem_ctx,
+                                       num_files,
+                                       files,
+                                       &state->ids);
+       if (!NT_STATUS_IS_OK(state->match_status)) {
+               return;
+       }
+
+       state->num_file_ids = num_files;
+       state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
+       return;
+}
+
+static void lease_match_parser(
+       uint32_t num_files,
+       const struct leases_db_file *files,
        void *private_data)
 {
-       struct lease_fname_match_state *state =
-               (struct lease_fname_match_state *)private_data;
+       struct lease_match_state *state =
+               (struct lease_match_state *)private_data;
+       uint32_t i;
 
-       if (!strequal(filename, state->fname->base_name) ||
-           !strequal(stream_name, state->fname->stream_name))
-       {
-               /* Names don't match lease key. */
-               state->match_status = NT_STATUS_INVALID_PARAMETER;
+       if (!state->file_existed) {
+               /*
+                * Deal with name mismatch or
+                * possible dynamic share case separately
+                * to make code clearer.
+                */
+               lease_match_parser_new_file(num_files,
+                                               files,
+                                               state);
                return;
        }
 
-       if (state->file_existed &&
-           num_file_ids == 1 &&
-           file_id_equal(&ids[0],&state->id))
-       {
-               /* Common case - non-dynamic share. We're ok.. */
-               state->match_status = NT_STATUS_OK;
+       /* File existed. */
+       state->match_status = NT_STATUS_OK;
+
+       for (i = 0; i < num_files; i++) {
+               const struct leases_db_file *f = &files[i];
+
+               /* Everything should be the same. */
+               if (!file_id_equal(&state->id, &f->id)) {
+                       /* This should catch all dynamic share cases. */
+                       state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
+                       break;
+               }
+               if (!strequal(f->servicepath, state->servicepath)) {
+                       state->match_status = NT_STATUS_INVALID_PARAMETER;
+                       break;
+               }
+               if (!strequal(f->base_name, state->fname->base_name)) {
+                       state->match_status = NT_STATUS_INVALID_PARAMETER;
+                       break;
+               }
+               if (!strequal(f->stream_name, state->fname->stream_name)) {
+                       state->match_status = NT_STATUS_INVALID_PARAMETER;
+                       break;
+               }
+       }
+
+       if (NT_STATUS_IS_OK(state->match_status)) {
+               /*
+                * Common case - just opening another handle on a
+                * file on a non-dynamic share.
+                */
+               return;
+       }
+
+       if (NT_STATUS_EQUAL(state->match_status, NT_STATUS_INVALID_PARAMETER)) {
+               /* Mismatched path. Error back to client. */
                return;
        }
 
        /*
-        * More than one file id, or not equal, or new file
-        * being created and there's already an existing lease
-        * on this (client_guid, lease id) pair.
+        * File id mismatch. Dynamic share case NT_STATUS_OPLOCK_NOT_GRANTED.
         * Don't allow leases.
         */
 
-       state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
-       state->num_file_ids = num_file_ids;
-       state->ids = talloc_memdup(talloc_tos(),
-                               ids,
-                               num_file_ids * sizeof(struct file_id));
-       if (state->ids == NULL) {
-               state->match_status = NT_STATUS_NO_MEMORY;
+       state->match_status = leases_db_copy_file_ids(state->mem_ctx,
+                                       num_files,
+                                       files,
+                                       &state->ids);
+       if (!NT_STATUS_IS_OK(state->match_status)) {
+               return;
        }
+
+       state->num_file_ids = num_files;
+       state->match_status = NT_STATUS_OPLOCK_NOT_GRANTED;
+       return;
 }
 
 static NTSTATUS lease_match(connection_struct *conn,
                            struct smb_request *req,
                            struct smb2_lease_key *lease_key,
+                           const char *servicepath,
                            const struct smb_filename *fname,
                            uint16_t *p_version,
                            uint16_t *p_epoch)
 {
        struct smbd_server_connection *sconn = req->sconn;
-       struct lease_fname_match_state state = {
+       TALLOC_CTX *tos = talloc_tos();
+       struct lease_match_state state = {
+               .mem_ctx = tos,
+               .servicepath = servicepath,
                .fname = fname,
                .match_status = NT_STATUS_OK
        };
@@ -4198,7 +4929,7 @@ static NTSTATUS lease_match(connection_struct *conn,
        }
 
        status = leases_db_parse(&sconn->client->connections->smb2.client.guid,
-                                lease_key, lease_fname_match_parser, &state);
+                                lease_key, lease_match_parser, &state);
        if (!NT_STATUS_IS_OK(status)) {
                /*
                 * Not found or error means okay: We can make the lease pass
@@ -4253,7 +4984,7 @@ static NTSTATUS lease_match(connection_struct *conn,
                                continue;
                        }
 
-                       send_break_message(conn->sconn->msg_ctx, e,
+                       send_break_message(conn->sconn->msg_ctx, &d->id, e,
                                           SMB2_LEASE_NONE);
 
                        /*
@@ -4351,6 +5082,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                status = lease_match(conn,
                                req,
                                &lease->lease_key,
+                               conn->connectpath,
                                smb_fname,
                                &version,
                                &epoch);
@@ -4371,7 +5103,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
                 * We can't open a file with DELETE access if any of the
                 * streams is open without FILE_SHARE_DELETE
                 */
-               status = open_streams_for_delete(conn, smb_fname->base_name);
+               status = open_streams_for_delete(conn, smb_fname);
 
                if (!NT_STATUS_IS_OK(status)) {
                        goto fail;
@@ -4391,7 +5123,7 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
        if ((conn->fs_capabilities & FILE_NAMED_STREAMS)
            && is_ntfs_stream_smb_fname(smb_fname)
            && (!(private_flags & NTCREATEX_OPTIONS_PRIVATE_STREAM_DELETE))) {
-               uint32 base_create_disposition;
+               uint32_t base_create_disposition;
                struct smb_filename *smb_fname_base = NULL;
 
                if (create_options & FILE_DIRECTORY_FILE) {
@@ -4410,8 +5142,10 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
 
                /* Create an smb_filename with stream_name == NULL. */
                smb_fname_base = synthetic_smb_fname(talloc_tos(),
-                                                    smb_fname->base_name,
-                                                    NULL, NULL);
+                                               smb_fname->base_name,
+                                               NULL,
+                                               NULL,
+                                               smb_fname->flags);
                if (smb_fname_base == NULL) {
                        status = NT_STATUS_NO_MEMORY;
                        goto fail;
@@ -4587,15 +5321,11 @@ static NTSTATUS create_file_unixpath(connection_struct *conn,
 
        /* Save the requested allocation size. */
        if ((info == FILE_WAS_CREATED) || (info == FILE_WAS_OVERWRITTEN)) {
-               if (allocation_size
-                   && (allocation_size > fsp->fsp_name->st.st_ex_size)) {
+               if ((allocation_size > fsp->fsp_name->st.st_ex_size)
+                   && !(fsp->is_directory))
+               {
                        fsp->initial_allocation_size = smb_roundup(
                                fsp->conn, allocation_size);
-                       if (fsp->is_directory) {
-                               /* Can't set allocation size on a directory. */
-                               status = NT_STATUS_ACCESS_DENIED;
-                               goto fail;
-                       }
                        if (vfs_allocate_file_space(
                                    fsp, fsp->initial_allocation_size) == -1) {
                                status = NT_STATUS_DISK_FULL;
@@ -4708,6 +5438,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
        files_struct *dir_fsp;
        char *parent_fname = NULL;
        char *new_base_name = NULL;
+       uint32_t ucf_flags = ucf_flags_from_smb_request(req);
        NTSTATUS status;
 
        if (root_dir_fid == 0 || !smb_fname) {
@@ -4800,9 +5531,8 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
 
        status = filename_convert(req,
                                conn,
-                               req->flags2 & FLAGS2_DFS_PATHNAMES,
                                new_base_name,
-                               0,
+                               ucf_flags,
                                NULL,
                                smb_fname_out);
        if (!NT_STATUS_IS_OK(status)) {
@@ -4831,7 +5561,9 @@ NTSTATUS create_file_default(connection_struct *conn,
                             struct security_descriptor *sd,
                             struct ea_list *ea_list,
                             files_struct **result,
-                            int *pinfo)
+                            int *pinfo,
+                            const struct smb2_create_blobs *in_context_blobs,
+                            struct smb2_create_blobs *out_context_blobs)
 {
        int info = FILE_WAS_OPENED;
        files_struct *fsp = NULL;
@@ -4917,7 +5649,7 @@ NTSTATUS create_file_default(connection_struct *conn,
                        status = NT_STATUS_NOT_A_DIRECTORY;
                        goto fail;
                }
-               if (lp_posix_pathnames()) {
+               if (req != NULL && req->posix_pathnames) {
                        ret = SMB_VFS_LSTAT(conn, smb_fname);
                } else {
                        ret = SMB_VFS_STAT(conn, smb_fname);