s3/smbd: add comments and some reformatting to open_file_ntcreate()
[samba.git] / source3 / smbd / open.c
index ca674b4b03080d24fede4a6a9ff6b262cde22b68..660a5bb6f6f8142cb50a8f3c1a40fef420abb4b0 100644 (file)
@@ -21,6 +21,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"
@@ -119,7 +120,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);
@@ -153,7 +154,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))) {
@@ -235,7 +236,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)
 {
@@ -243,6 +244,7 @@ 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;
 
        if (!parent_dirname(talloc_tos(),
                                smb_fname->base_name,
@@ -251,6 +253,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 "
@@ -261,7 +272,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);
@@ -362,7 +373,7 @@ NTSTATUS fd_open(struct connection_struct *conn,
         * 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
@@ -448,8 +459,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;
        }
@@ -506,8 +520,11 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
        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;
        }
@@ -547,7 +564,7 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
                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;
@@ -583,8 +600,10 @@ NTSTATUS change_dir_owner_to_parent(connection_struct *conn,
        }
 
        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);
@@ -621,7 +640,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;
 
@@ -653,59 +674,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;
 }
 
@@ -719,8 +746,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;
@@ -809,6 +836,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;
                }
@@ -882,6 +910,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. */
@@ -911,7 +958,7 @@ static NTSTATUS open_file(files_struct *fsp,
                        }
 
                        /* 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;
@@ -945,7 +992,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
@@ -1014,8 +1061,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, "
@@ -1130,7 +1177,7 @@ static void validate_my_share_entries(struct smbd_server_connection *sconn,
                          "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;
        }
 
@@ -1152,7 +1199,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|
@@ -1191,10 +1238,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;
@@ -1261,14 +1308,14 @@ NTSTATUS send_break_message(struct messaging_context *msg_ctx,
 
        /* 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)));
@@ -1433,7 +1480,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;
                }
@@ -1933,9 +1980,9 @@ static void defer_open(struct share_mode_lock *lck,
                DEBUG(10, ("defering mid %llu\n",
                           (unsigned long long)req->mid));
 
-               watch_req = dbwrap_record_watch_send(
+               watch_req = dbwrap_watched_watch_send(
                        watch_state, req->sconn->ev_ctx, lck->data->record,
-                       req->sconn->msg_ctx);
+                       (struct server_id){0});
                if (watch_req == NULL) {
                        exit_server("Could not watch share mode record");
                }
@@ -1962,10 +2009,11 @@ 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, talloc_tos(), NULL, 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
@@ -1986,13 +2034,13 @@ static void defer_open_done(struct tevent_req *req)
 ****************************************************************************/
 
 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);
@@ -2038,11 +2086,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;
 
@@ -2170,7 +2218,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),
@@ -2235,6 +2283,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.
         */
@@ -2354,7 +2408,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;
@@ -2390,11 +2443,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.) */
@@ -2414,10 +2467,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;
@@ -2517,7 +2570,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;
+                       }
                }
        }
 
@@ -2529,7 +2593,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 "
@@ -2641,8 +2706,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.
@@ -2705,7 +2769,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;
@@ -2732,9 +2798,16 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
        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"));
@@ -2765,8 +2838,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);
@@ -2887,19 +2962,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));
@@ -3047,7 +3134,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);
@@ -3065,6 +3152,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 ){
 
@@ -3073,6 +3169,8 @@ static NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        return NT_STATUS_SHARING_VIOLATION;
                }
+
+               fsp->kernel_share_modes_taken = true;
        }
 
        /*
@@ -3158,8 +3256,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,
@@ -3243,7 +3341,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;
@@ -3282,7 +3380,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);
        }
 
@@ -3324,7 +3422,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;
@@ -3332,7 +3430,7 @@ 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->st);
@@ -3360,11 +3458,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)
 {
@@ -3479,6 +3577,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;
                                }
                        }
@@ -3543,7 +3660,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);
@@ -3592,8 +3711,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)));
@@ -3759,8 +3888,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;
        }
@@ -3806,8 +3938,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;
@@ -3816,7 +3948,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)
@@ -3848,30 +3980,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),
@@ -3890,13 +4026,13 @@ NTSTATUS open_streams_for_delete(connection_struct *conn,
 
                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);
        }
 
        /*
@@ -3936,7 +4072,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;
@@ -3945,14 +4082,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);
@@ -4460,7 +4608,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;
@@ -4480,7 +4628,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) {
@@ -4499,8 +4647,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;
@@ -4676,15 +4826,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;
@@ -4797,6 +4943,8 @@ 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 = ((req != NULL && req->posix_pathnames) ?
+                       UCF_POSIX_PATHNAMES : 0);
        NTSTATUS status;
 
        if (root_dir_fid == 0 || !smb_fname) {
@@ -4891,7 +5039,7 @@ NTSTATUS get_relative_fid_filename(connection_struct *conn,
                                conn,
                                req->flags2 & FLAGS2_DFS_PATHNAMES,
                                new_base_name,
-                               0,
+                               ucf_flags,
                                NULL,
                                smb_fname_out);
        if (!NT_STATUS_IS_OK(status)) {
@@ -5008,7 +5156,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);