Fix bug #6082 - smbd_gpfs_getacl failed: Windows client canĀ“t rename or delete file
[samba.git] / source / smbd / open.c
index f55728665fb1e25351dc69f221b2be3902c5702a..7e127eafbf4d70c4e5ca56db92a0c08a497bbcb5 100644 (file)
@@ -22,8 +22,6 @@
 #include "includes.h"
 
 extern const struct generic_mapping file_generic_mapping;
-extern struct current_user current_user;
-extern userdom_struct current_user_info;
 extern bool global_client_failed_oplock_break;
 
 struct deferred_open_record {
@@ -31,6 +29,66 @@ struct deferred_open_record {
        struct file_id id;
 };
 
+/****************************************************************************
+ SMB1 file varient of se_access_check. Never test FILE_READ_ATTRIBUTES.
+****************************************************************************/
+
+NTSTATUS smb1_file_se_access_check(const struct security_descriptor *sd,
+                          const NT_USER_TOKEN *token,
+                          uint32_t access_desired,
+                          uint32_t *access_granted)
+{
+       return se_access_check(sd,
+                               token,
+                               (access_desired & ~FILE_READ_ATTRIBUTES),
+                               access_granted);
+}
+
+/****************************************************************************
+ Check if we have open rights.
+****************************************************************************/
+
+static NTSTATUS check_open_rights(struct connection_struct *conn,
+                               const char *fname,
+                               uint32_t access_mask,
+                               uint32_t *access_granted)
+{
+       /* Check if we have rights to open. */
+       NTSTATUS status;
+       struct security_descriptor *sd;
+
+       *access_granted = 0;
+
+       status = SMB_VFS_GET_NT_ACL(conn, fname,
+                       (OWNER_SECURITY_INFORMATION |
+                       GROUP_SECURITY_INFORMATION |
+                       DACL_SECURITY_INFORMATION),&sd);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("check_open_rights: Could not get acl "
+                       "on %s: %s\n",
+                       fname,
+                       nt_errstr(status)));
+               return status;
+       }
+
+       status = smb1_file_se_access_check(sd,
+                               conn->server_info->ptok,
+                               access_mask,
+                               access_granted);
+
+       TALLOC_FREE(sd);
+
+       DEBUG(10,("check_open_rights: file %s requesting "
+               "0x%x returning 0x%x (%s)\n",
+               fname,
+               (unsigned int)access_mask,
+               (unsigned int)*access_granted,
+               nt_errstr(status) ));
+
+       return status;
+}
+
 /****************************************************************************
  fd support routines - attempt to do a dos_open.
 ****************************************************************************/
@@ -72,13 +130,21 @@ static NTSTATUS fd_open(struct connection_struct *conn,
 
 NTSTATUS fd_close(files_struct *fsp)
 {
+       int ret;
+
        if (fsp->fh->fd == -1) {
                return NT_STATUS_OK; /* What we used to call a stat open. */
        }
        if (fsp->fh->ref_count > 1) {
                return NT_STATUS_OK; /* Shared handle. Only close last reference. */
        }
-       return fd_close_posix(fsp);
+
+       ret = SMB_VFS_CLOSE(fsp);
+       fsp->fh->fd = -1;
+       if (ret == -1) {
+               return map_nt_error_from_unix(errno);
+       }
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -276,6 +342,7 @@ static NTSTATUS open_file(files_struct *fsp,
        if ((open_access_mask & (FILE_READ_DATA|FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_EXECUTE)) ||
            (!file_existed && (local_flags & O_CREAT)) ||
            ((local_flags & O_TRUNC) == O_TRUNC) ) {
+               const char *wild;
 
                /*
                 * We can't actually truncate here as the file may be locked.
@@ -297,8 +364,17 @@ static NTSTATUS open_file(files_struct *fsp,
 #endif
 
                /* Don't create files with Microsoft wildcard characters. */
+               if (fsp->base_fsp) {
+                       /*
+                        * wildcard characters are allowed in stream names
+                        * only test the basefilename
+                        */
+                       wild = fsp->base_fsp->fsp_name;
+               } else {
+                       wild = path;
+               }
                if ((local_flags & O_CREAT) && !file_existed &&
-                   ms_has_wild(path))  {
+                   ms_has_wild(wild))  {
                        return NT_STATUS_OBJECT_NAME_INVALID;
                }
 
@@ -315,7 +391,7 @@ static NTSTATUS open_file(files_struct *fsp,
 
                        /* Inherit the ACL if required */
                        if (lp_inherit_perms(SNUM(conn))) {
-                               inherit_access_acl(conn, parent_dir, path,
+                               inherit_access_posix_acl(conn, parent_dir, path,
                                                   unx_mode);
                        }
 
@@ -331,6 +407,38 @@ static NTSTATUS open_file(files_struct *fsp,
 
        } else {
                fsp->fh->fd = -1; /* What we used to call a stat open. */
+               if (file_existed) {
+                       uint32_t access_granted = 0;
+
+                       status = check_open_rights(conn,
+                                       path,
+                                       access_mask,
+                                       &access_granted);
+                       if (!NT_STATUS_IS_OK(status)) {
+
+                               /* Were we trying to do a stat open
+                                * for delete and didn't get DELETE
+                                * access (only) ? Check if the
+                                * directory allows DELETE_CHILD.
+                                * See here:
+                                * http://blogs.msdn.com/oldnewthing/archive/2004/06/04/148426.aspx
+                                * for details. */
+
+                               if (!(NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) &&
+                                               (access_mask & DELETE_ACCESS) &&
+                                               (access_granted == DELETE_ACCESS) &&
+                                               can_delete_file_in_directory(conn, path))) {
+                                       DEBUG(10, ("open_file: Access denied on "
+                                               "file %s\n",
+                                               path));
+                                       return status;
+                               }
+
+                               DEBUG(10,("open_file: overrode ACCESS_DENIED "
+                                       "on file %s\n",
+                                       path ));
+                       }
+               }
        }
 
        if (!file_existed) {
@@ -383,7 +491,6 @@ static NTSTATUS open_file(files_struct *fsp,
        fsp->modified = False;
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = False;
-       fsp->is_stat = False;
        if (conn->aio_write_behind_list &&
            is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) {
                fsp->aio_write_behind = True;
@@ -393,10 +500,10 @@ static NTSTATUS open_file(files_struct *fsp,
        fsp->wcp = NULL; /* Write cache pointer. */
 
        DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n",
-                *current_user_info.smb_name ?
-                current_user_info.smb_name : conn->user,fsp->fsp_name,
+                conn->server_info->unix_name,
+                fsp->fsp_name,
                 BOOLSTR(fsp->can_read), BOOLSTR(fsp->can_write),
-                conn->num_files_open + 1));
+                conn->num_files_open));
 
        errno = 0;
        return NT_STATUS_OK;
@@ -648,13 +755,52 @@ static bool is_delete_request(files_struct *fsp) {
                (fsp->oplock_type == NO_OPLOCK));
 }
 
+/*
+ * Send a break message to the oplock holder and delay the open for
+ * our client.
+ */
+
+static NTSTATUS send_break_message(files_struct *fsp,
+                                       struct share_mode_entry *exclusive,
+                                       uint16 mid,
+                                       int oplock_request)
+{
+       NTSTATUS status;
+       char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+
+       DEBUG(10, ("Sending break request to PID %s\n",
+                  procid_str_static(&exclusive->pid)));
+       exclusive->op_mid = mid;
+
+       /* Create the message. */
+       share_mode_entry_to_message(msg, exclusive);
+
+       /* Add in the FORCE_OPLOCK_BREAK_TO_NONE bit in the message if set. We
+          don't want this set in the share mode struct pointed to by lck. */
+
+       if (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE) {
+               SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
+       }
+
+       status = messaging_send_buf(smbd_messaging_context(), exclusive->pid,
+                                   MSG_SMB_BREAK_REQUEST,
+                                   (uint8 *)msg,
+                                   MSG_SMB_SHARE_MODE_ENTRY_SIZE);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(3, ("Could not send oplock break message: %s\n",
+                         nt_errstr(status)));
+       }
+
+       return status;
+}
+
 /*
  * 1) No files open at all or internal open: Grant whatever the client wants.
  *
  * 2) Exclusive (or batch) oplock around: If the requested access is a delete
  *    request, break if the oplock around is a batch oplock. If it's another
  *    requested access type, break.
- * 
+ *
  * 3) Only level2 around: Grant level2 and do nothing else.
  */
 
@@ -664,20 +810,21 @@ static bool delay_for_oplocks(struct share_mode_lock *lck,
                              int pass_number,
                              int oplock_request)
 {
+       extern uint32 global_client_caps;
        int i;
        struct share_mode_entry *exclusive = NULL;
-       bool valid_entry = False;
-       bool delay_it = False;
-       bool have_level2 = False;
-       NTSTATUS status;
-       char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE];
+       bool valid_entry = false;
+       bool have_level2 = false;
+       bool have_a_none_oplock = false;
+       bool allow_level2 = (global_client_caps & CAP_LEVEL_II_OPLOCKS) &&
+                           lp_level2_oplocks(SNUM(fsp->conn));
 
        if (oplock_request & INTERNAL_OPEN_ONLY) {
                fsp->oplock_type = NO_OPLOCK;
        }
 
        if ((oplock_request & INTERNAL_OPEN_ONLY) || is_stat_open(fsp->access_mask)) {
-               return False;
+               return false;
        }
 
        for (i=0; i<lck->num_share_modes; i++) {
@@ -687,86 +834,80 @@ static bool delay_for_oplocks(struct share_mode_lock *lck,
                }
 
                /* At least one entry is not an invalid or deferred entry. */
-               valid_entry = True;
+               valid_entry = true;
 
                if (pass_number == 1) {
                        if (BATCH_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
-                               SMB_ASSERT(exclusive == NULL);                  
+                               SMB_ASSERT(exclusive == NULL);
                                exclusive = &lck->share_modes[i];
                        }
                } else {
                        if (EXCLUSIVE_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
-                               SMB_ASSERT(exclusive == NULL);                  
+                               SMB_ASSERT(exclusive == NULL);
                                exclusive = &lck->share_modes[i];
                        }
                }
 
-               if (lck->share_modes[i].op_type == LEVEL_II_OPLOCK) {
-                       SMB_ASSERT(exclusive == NULL);                  
-                       have_level2 = True;
+               if (LEVEL_II_OPLOCK_TYPE(lck->share_modes[i].op_type)) {
+                       SMB_ASSERT(exclusive == NULL);
+                       have_level2 = true;
                }
-       }
 
-       if (!valid_entry) {
-               /* All entries are placeholders or deferred.
-                * Directly grant whatever the client wants. */
-               if (fsp->oplock_type == NO_OPLOCK) {
-                       /* Store a level2 oplock, but don't tell the client */
-                       fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+               if (lck->share_modes[i].op_type == NO_OPLOCK) {
+                       have_a_none_oplock = true;
                }
-               return False;
        }
 
        if (exclusive != NULL) { /* Found an exclusive oplock */
+               bool delay_it = is_delete_request(fsp) ?
+                               BATCH_OPLOCK_TYPE(exclusive->op_type) : true;
                SMB_ASSERT(!have_level2);
-               delay_it = is_delete_request(fsp) ?
-                       BATCH_OPLOCK_TYPE(exclusive->op_type) : True;
-       }
-
-       if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
-               /* We can at most grant level2 as there are other
-                * level2 or NO_OPLOCK entries. */
-               fsp->oplock_type = LEVEL_II_OPLOCK;
+               if (delay_it) {
+                       send_break_message(fsp, exclusive, mid, oplock_request);
+                       return true;
+               }
        }
 
-       if ((fsp->oplock_type == NO_OPLOCK) && have_level2) {
-               /* Store a level2 oplock, but don't tell the client */
-               fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
-       }
+       /*
+        * Match what was requested (fsp->oplock_type) with
+        * what was found in the existing share modes.
+        */
 
-       if (!delay_it) {
-               return False;
+       if (!valid_entry) {
+               /* All entries are placeholders or deferred.
+                * Directly grant whatever the client wants. */
+               if (fsp->oplock_type == NO_OPLOCK) {
+                       /* Store a level2 oplock, but don't tell the client */
+                       fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+               }
+       } else if (have_a_none_oplock) {
+               fsp->oplock_type = NO_OPLOCK;
+       } else if (have_level2) {
+               if (fsp->oplock_type == NO_OPLOCK ||
+                               fsp->oplock_type == FAKE_LEVEL_II_OPLOCK) {
+                       /* Store a level2 oplock, but don't tell the client */
+                       fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
+               } else {
+                       fsp->oplock_type = LEVEL_II_OPLOCK;
+               }
+       } else {
+               /* This case can never happen. */
+               SMB_ASSERT(1);
        }
 
        /*
-        * Send a break message to the oplock holder and delay the open for
-        * our client.
+        * Don't grant level2 to clients that don't want them
+        * or if we've turned them off.
         */
-
-       DEBUG(10, ("Sending break request to PID %s\n",
-                  procid_str_static(&exclusive->pid)));
-       exclusive->op_mid = mid;
-
-       /* Create the message. */
-       share_mode_entry_to_message(msg, exclusive);
-
-       /* Add in the FORCE_OPLOCK_BREAK_TO_NONE bit in the message if set. We
-          don't want this set in the share mode struct pointed to by lck. */
-
-       if (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE) {
-               SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE);
+       if (fsp->oplock_type == LEVEL_II_OPLOCK && !allow_level2) {
+               fsp->oplock_type = FAKE_LEVEL_II_OPLOCK;
        }
 
-       status = messaging_send_buf(smbd_messaging_context(), exclusive->pid,
-                                   MSG_SMB_BREAK_REQUEST,
-                                   (uint8 *)msg,
-                                   MSG_SMB_SHARE_MODE_ENTRY_SIZE);
-       if (!NT_STATUS_IS_OK(status)) {
-               DEBUG(3, ("Could not send oplock break message: %s\n",
-                         nt_errstr(status)));
-       }
+       DEBUG(10,("delay_for_oplocks: oplock type 0x%x on file %s\n",
+               fsp->oplock_type, fsp->fsp_name));
 
-       return True;
+       /* No delay. */
+       return false;
 }
 
 static bool request_timed_out(struct timeval request_time,
@@ -885,7 +1026,8 @@ static bool open_match_attributes(connection_struct *conn,
  Try and find a duplicated file handle.
 ****************************************************************************/
 
-static files_struct *fcb_or_dos_open(connection_struct *conn,
+static NTSTATUS fcb_or_dos_open(connection_struct *conn,
+                                    files_struct *fsp_to_dup_into,
                                     const char *fname, 
                                     struct file_id id,
                                     uint16 file_pid,
@@ -895,7 +1037,6 @@ static files_struct *fcb_or_dos_open(connection_struct *conn,
                                     uint32 create_options)
 {
        files_struct *fsp;
-       files_struct *dup_fsp;
 
        DEBUG(5,("fcb_or_dos_open: attempting old open semantics for "
                 "file %s.\n", fname ));
@@ -924,23 +1065,21 @@ static files_struct *fcb_or_dos_open(connection_struct *conn,
        }
 
        if (!fsp) {
-               return NULL;
+               return NT_STATUS_NOT_FOUND;
        }
 
        /* quite an insane set of semantics ... */
        if (is_executable(fname) &&
            (fsp->fh->private_options & NTCREATEX_OPTIONS_PRIVATE_DENY_DOS)) {
                DEBUG(10,("fcb_or_dos_open: file fail due to is_executable.\n"));
-               return NULL;
+               return NT_STATUS_INVALID_PARAMETER;
        }
 
        /* We need to duplicate this fsp. */
-       if (!NT_STATUS_IS_OK(dup_file_fsp(fsp, access_mask, share_access,
-                                         create_options, &dup_fsp))) {
-               return NULL;
-       }
+       dup_file_fsp(fsp, access_mask, share_access,
+                         create_options, fsp_to_dup_into);
 
-       return dup_fsp;
+       return NT_STATUS_OK;
 }
 
 /****************************************************************************
@@ -956,7 +1095,7 @@ bool map_open_params_to_ntcreate(const char *fname, int deny_mode, int open_func
        uint32 access_mask;
        uint32 share_mode;
        uint32 create_disposition;
-       uint32 create_options = 0;
+       uint32 create_options = FILE_NON_DIRECTORY_FILE;
 
        DEBUG(10,("map_open_params_to_ntcreate: fname = %s, deny_mode = 0x%x, "
                  "open_func = 0x%x\n",
@@ -1120,10 +1259,72 @@ static void schedule_defer_open(struct share_mode_lock *lck,
 }
 
 /****************************************************************************
Open a file with a share mode.
Work out what access_mask to use from what the client sent us.
 ****************************************************************************/
 
-NTSTATUS open_file_ntcreate(connection_struct *conn,
+static NTSTATUS calculate_access_mask(connection_struct *conn,
+                                       const char *fname,
+                                       bool file_existed,
+                                       uint32_t access_mask,
+                                       uint32_t *access_mask_out)
+{
+       NTSTATUS status;
+
+       /*
+        * Convert GENERIC bits to specific bits.
+        */
+
+       se_map_generic(&access_mask, &file_generic_mapping);
+
+       /* Calculate MAXIMUM_ALLOWED_ACCESS if requested. */
+       if (access_mask & MAXIMUM_ALLOWED_ACCESS) {
+               if (file_existed) {
+
+                       struct security_descriptor *sd;
+                       uint32_t access_granted = 0;
+
+                       status = SMB_VFS_GET_NT_ACL(conn, fname,
+                                       (OWNER_SECURITY_INFORMATION |
+                                       GROUP_SECURITY_INFORMATION |
+                                       DACL_SECURITY_INFORMATION),&sd);
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(10, ("calculate_access_mask: Could not get acl "
+                                       "on file %s: %s\n",
+                                       fname,
+                                       nt_errstr(status)));
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+
+                       status = smb1_file_se_access_check(sd,
+                                       conn->server_info->ptok,
+                                       access_mask,
+                                       &access_granted);
+
+                       TALLOC_FREE(sd);
+
+                       if (!NT_STATUS_IS_OK(status)) {
+                               DEBUG(10, ("calculate_access_mask: Access denied on "
+                                       "file %s: when calculating maximum access\n",
+                                       fname));
+                               return NT_STATUS_ACCESS_DENIED;
+                       }
+
+                       access_mask = access_granted;
+               } else {
+                       access_mask = FILE_GENERIC_ALL;
+               }
+       }
+
+       *access_mask_out = access_mask;
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a file with a share mode. Passed in an already created files_struct *.
+****************************************************************************/
+
+static NTSTATUS open_file_ntcreate_internal(connection_struct *conn,
                            struct smb_request *req,
                            const char *fname,
                            SMB_STRUCT_STAT *psbuf,
@@ -1135,7 +1336,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                            int oplock_request,         /* internal Samba oplock codes. */
                                                        /* Information (FILE_EXISTS etc.) */
                            int *pinfo,
-                           files_struct **result)
+                           files_struct *fsp)
 {
        int flags=0;
        int flags2=0;
@@ -1145,7 +1346,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        bool new_file_created = False;
        struct file_id id;
        NTSTATUS fsp_open = NT_STATUS_ACCESS_DENIED;
-       files_struct *fsp = NULL;
        mode_t new_unx_mode = (mode_t)0;
        mode_t unx_mode = (mode_t)0;
        int info;
@@ -1162,7 +1362,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        ZERO_STRUCT(id);
 
        if (conn->printer) {
-               /* 
+               /*
                 * Printers are handled completely differently.
                 * Most of the passed parameters are ignored.
                 */
@@ -1173,7 +1373,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                DEBUG(10, ("open_file_ntcreate: printer open fname=%s\n", fname));
 
-               return print_fsp_open(conn, fname, result);
+               return print_fsp_open(conn, fname, req->vuid, fsp, psbuf);
        }
 
        if (!parent_dirname_talloc(talloc_tos(), fname, &parent_dir,
@@ -1221,7 +1421,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                request_time = pml->request_time;
 
                /* Remove the deferred open entry under lock. */
-               lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL);
+               lck = get_share_mode_lock(talloc_tos(), state->id, NULL, NULL,
+                                         NULL);
                if (lck == NULL) {
                        DEBUG(0, ("could not get share mode lock\n"));
                } else {
@@ -1354,19 +1555,20 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                }
        }
 
-       /* This is a nasty hack - must fix... JRA. */
-       if (access_mask == MAXIMUM_ALLOWED_ACCESS) {
-               open_access_mask = access_mask = FILE_GENERIC_ALL;
+       status = calculate_access_mask(conn, fname, file_existed,
+                                       access_mask,
+                                       &access_mask); 
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("open_file_ntcreate: calculate_access_mask "
+                       "on file %s returned %s\n",
+                       fname,
+                       nt_errstr(status)));
+               return status;
        }
 
-       /*
-        * Convert GENERIC bits to specific bits.
-        */
-
-       se_map_generic(&access_mask, &file_generic_mapping);
        open_access_mask = access_mask;
 
-       if (flags2 & O_TRUNC) {
+       if ((flags2 & O_TRUNC) || (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
                open_access_mask |= FILE_WRITE_DATA; /* This will cause oplock breaks. */
        }
 
@@ -1378,7 +1580,8 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * mean the same thing under DOS and Unix.
         */
 
-       if (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) {
+       if ((access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ||
+                       (oplock_request & FORCE_OPLOCK_BREAK_TO_NONE)) {
                /* DENY_DOS opens are always underlying read-write on the
                   file handle, no matter what the requested access mask
                    says. */
@@ -1428,11 +1631,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                return NT_STATUS_ACCESS_DENIED;
        }
 
-       status = file_new(conn, &fsp);
-       if(!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
        fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
        fsp->share_access = share_access;
        fsp->fh->private_options = create_options;
@@ -1449,14 +1647,14 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
 
        if (file_existed) {
+               struct timespec old_write_time = get_mtimespec(psbuf);
                id = vfs_file_id_from_sbuf(conn, psbuf);
 
                lck = get_share_mode_lock(talloc_tos(), id,
                                          conn->connectpath,
-                                         fname);
+                                         fname, &old_write_time);
 
                if (lck == NULL) {
-                       file_free(fsp);
                        DEBUG(0, ("Could not get share mode lock\n"));
                        return NT_STATUS_SHARING_VIOLATION;
                }
@@ -1467,7 +1665,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                                         oplock_request)) {
                        schedule_defer_open(lck, request_time, req);
                        TALLOC_FREE(lck);
-                       file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
@@ -1487,7 +1684,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                                                  oplock_request)) {
                                schedule_defer_open(lck, request_time, req);
                                TALLOC_FREE(lck);
-                               file_free(fsp);
                                return NT_STATUS_SHARING_VIOLATION;
                        }
                }
@@ -1495,7 +1691,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (NT_STATUS_EQUAL(status, NT_STATUS_DELETE_PENDING)) {
                        /* DELETE_PENDING is not deferred for a second */
                        TALLOC_FREE(lck);
-                       file_free(fsp);
                        return status;
                }
 
@@ -1510,33 +1705,30 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        if (create_options &
                            (NTCREATEX_OPTIONS_PRIVATE_DENY_DOS|
                             NTCREATEX_OPTIONS_PRIVATE_DENY_FCB)) {
-                               files_struct *fsp_dup;
-
                                if (req == NULL) {
                                        DEBUG(0, ("DOS open without an SMB "
                                                  "request!\n"));
                                        TALLOC_FREE(lck);
-                                       file_free(fsp);
                                        return NT_STATUS_INTERNAL_ERROR;
                                }
 
                                /* Use the client requested access mask here,
                                 * not the one we open with. */
-                               fsp_dup = fcb_or_dos_open(conn, fname, id,
+                               status = fcb_or_dos_open(conn,
+                                                         fsp,
+                                                         fname,
+                                                         id,
                                                          req->smbpid,
                                                          req->vuid,
                                                          access_mask,
                                                          share_access,
                                                          create_options);
 
-                               if (fsp_dup) {
+                               if (NT_STATUS_IS_OK(status)) {
                                        TALLOC_FREE(lck);
-                                       file_free(fsp);
                                        if (pinfo) {
                                                *pinfo = FILE_WAS_OPENED;
                                        }
-                                       conn->num_files_open++;
-                                       *result = fsp_dup;
                                        return NT_STATUS_OK;
                                }
                        }
@@ -1560,7 +1752,7 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        }
 
                        if (((can_access_mask & FILE_WRITE_DATA) && !CAN_WRITE(conn)) ||
-                           !can_access_file(conn,fname,psbuf,can_access_mask)) {
+                           !can_access_file_data(conn,fname,psbuf,can_access_mask)) {
                                can_access = False;
                        }
 
@@ -1617,7 +1809,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        } else {
                                status = NT_STATUS_ACCESS_DENIED;
                        }
-                       file_free(fsp);
                        return status;
                }
 
@@ -1655,12 +1846,11 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                if (lck != NULL) {
                        TALLOC_FREE(lck);
                }
-               file_free(fsp);
                return fsp_open;
        }
 
        if (!file_existed) {
-
+               struct timespec old_write_time = get_mtimespec(psbuf);
                /*
                 * Deal with the race condition where two smbd's detect the
                 * file doesn't exist and do the create at the same time. One
@@ -1680,13 +1870,12 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                lck = get_share_mode_lock(talloc_tos(), id,
                                          conn->connectpath,
-                                         fname);
+                                         fname, &old_write_time);
 
                if (lck == NULL) {
                        DEBUG(0, ("open_file_ntcreate: Could not get share "
                                  "mode lock for %s\n", fname));
                        fd_close(fsp);
-                       file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
@@ -1697,7 +1886,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        schedule_defer_open(lck, request_time, req);
                        TALLOC_FREE(lck);
                        fd_close(fsp);
-                       file_free(fsp);
                        return NT_STATUS_SHARING_VIOLATION;
                }
 
@@ -1716,7 +1904,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                                schedule_defer_open(lck, request_time, req);
                                TALLOC_FREE(lck);
                                fd_close(fsp);
-                               file_free(fsp);
                                return NT_STATUS_SHARING_VIOLATION;
                        }
                }
@@ -1725,7 +1912,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        struct deferred_open_record state;
 
                        fd_close(fsp);
-                       file_free(fsp);
 
                        state.delayed_for_oplocks = False;
                        state.id = id;
@@ -1767,7 +1953,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
 
                        TALLOC_FREE(lck);
                        fd_close(fsp);
-                       file_free(fsp);
 
                        return NT_STATUS_SHARING_VIOLATION;
                }
@@ -1793,7 +1978,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        status = map_nt_error_from_unix(errno);
                        TALLOC_FREE(lck);
                        fd_close(fsp);
-                       file_free(fsp);
                        return status;
                }
        }
@@ -1801,7 +1985,10 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        /* Record the options we were opened with. */
        fsp->share_access = share_access;
        fsp->fh->private_options = create_options;
-       fsp->access_mask = access_mask;
+       /*
+        * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted,
+        */
+       fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES;
 
        if (file_existed) {
                /* stat opens on existing files don't get oplocks. */
@@ -1827,24 +2014,21 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
         * file structs.
         */
 
-       if ((fsp->oplock_type != NO_OPLOCK) &&
-           (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
-               if (!set_file_oplock(fsp, fsp->oplock_type)) {
-                       /* Could not get the kernel oplock */
-                       fsp->oplock_type = NO_OPLOCK;
-               }
+       if (!set_file_oplock(fsp, fsp->oplock_type)) {
+               /* Could not get the kernel oplock */
+               fsp->oplock_type = NO_OPLOCK;
        }
 
        if (info == FILE_WAS_OVERWRITTEN || info == FILE_WAS_CREATED || info == FILE_WAS_SUPERSEDED) {
                new_file_created = True;
        }
 
-       set_share_mode(lck, fsp, current_user.ut.uid, 0, fsp->oplock_type, new_file_created);
+       set_share_mode(lck, fsp, conn->server_info->utok.uid, 0,
+                      fsp->oplock_type);
 
        /* Handle strange delete on close create semantics. */
-       if ((create_options & FILE_DELETE_ON_CLOSE)
-           && (is_ntfs_stream_name(fname)
-               || can_set_initial_delete_on_close(lck))) {
+       if (create_options & FILE_DELETE_ON_CLOSE) {
+
                status = can_set_delete_on_close(fsp, True, new_dos_attributes);
 
                if (!NT_STATUS_IS_OK(status)) {
@@ -1852,7 +2036,6 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
                        del_share_mode(lck, fsp);
                        TALLOC_FREE(lck);
                        fd_close(fsp);
-                       file_free(fsp);
                        return status;
                }
                /* Note that here we set the *inital* delete on close flag,
@@ -1928,10 +2111,57 @@ NTSTATUS open_file_ntcreate(connection_struct *conn,
        }
        TALLOC_FREE(lck);
 
-       conn->num_files_open++;
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Open a file with a share mode.
+****************************************************************************/
+
+NTSTATUS open_file_ntcreate(connection_struct *conn,
+                           struct smb_request *req,
+                           const char *fname,
+                           SMB_STRUCT_STAT *psbuf,
+                           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. */
+                           int oplock_request,         /* internal Samba oplock codes. */
+                                                       /* Information (FILE_EXISTS etc.) */
+                           int *pinfo,
+                           files_struct **result)
+{
+       NTSTATUS status;
+       files_struct *fsp = NULL;
+
+       *result = NULL;
+
+       status = file_new(conn, &fsp);
+       if(!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       status = open_file_ntcreate_internal(conn,
+                                       req,
+                                       fname,
+                                       psbuf,
+                                       access_mask,
+                                       share_access,
+                                       create_disposition,
+                                       create_options,
+                                       new_dos_attributes,
+                                       oplock_request,
+                                       pinfo,
+                                       fsp);
+
+       if(!NT_STATUS_IS_OK(status)) {
+               file_free(fsp);
+               return status;
+       }
 
        *result = fsp;
-       return NT_STATUS_OK;
+       return status;
 }
 
 /****************************************************************************
@@ -1958,10 +2188,9 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname,
        status = open_file(fsp, conn, NULL, NULL, NULL, fname, psbuf, O_WRONLY,
                           0, FILE_WRITE_DATA, FILE_WRITE_DATA);
 
-       /* 
+       /*
         * This is not a user visible file open.
-        * Don't set a share mode and don't increment
-        * the conn->num_files_open.
+        * Don't set a share mode.
         */
 
        if (!NT_STATUS_IS_OK(status)) {
@@ -2047,7 +2276,7 @@ static NTSTATUS mkdir_internal(connection_struct *conn,
        }
 
        if (lp_inherit_perms(SNUM(conn))) {
-               inherit_access_acl(conn, parent_dir, name, mode);
+               inherit_access_posix_acl(conn, parent_dir, name, mode);
        }
 
        if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS)) {
@@ -2094,6 +2323,7 @@ NTSTATUS open_directory(connection_struct *conn,
        bool dir_existed = VALID_STAT(*psbuf) ? True : False;
        struct share_mode_lock *lck = NULL;
        NTSTATUS status;
+       struct timespec mtimespec;
        int info = 0;
 
        DEBUG(5,("open_directory: opening directory %s, access_mask = 0x%x, "
@@ -2106,11 +2336,24 @@ NTSTATUS open_directory(connection_struct *conn,
                 (unsigned int)create_disposition,
                 (unsigned int)file_attributes));
 
-       if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) && is_ntfs_stream_name(fname)) {
+       if (!(file_attributes & FILE_FLAG_POSIX_SEMANTICS) &&
+                       (conn->fs_capabilities & FILE_NAMED_STREAMS) &&
+                       is_ntfs_stream_name(fname)) {
                DEBUG(2, ("open_directory: %s is a stream name!\n", fname));
                return NT_STATUS_NOT_A_DIRECTORY;
        }
 
+       status = calculate_access_mask(conn, fname, dir_existed,
+                                       access_mask,
+                                       &access_mask); 
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("open_directory: calculate_access_mask "
+                       "on file %s returned %s\n",
+                       fname,
+                       nt_errstr(status)));
+               return status;
+       }
+
        switch( create_disposition ) {
                case FILE_OPEN:
 
@@ -2185,6 +2428,21 @@ NTSTATUS open_directory(connection_struct *conn,
                return NT_STATUS_NOT_A_DIRECTORY;
        }
 
+       if (info == FILE_WAS_OPENED) {
+               uint32_t access_granted = 0;
+               status = check_open_rights(conn,
+                                       fname,
+                                       access_mask,
+                                       &access_granted);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(10, ("open_directory: check_open_rights on "
+                               "file  %s failed with %s\n",
+                               fname,
+                               nt_errstr(status)));
+                       return status;
+               }
+       }
+
        status = file_new(conn, &fsp);
        if(!NT_STATUS_IS_OK(status)) {
                return status;
@@ -2204,21 +2462,24 @@ NTSTATUS open_directory(connection_struct *conn,
 
        fsp->share_access = share_access;
        fsp->fh->private_options = create_options;
-       fsp->access_mask = access_mask;
-
+       /*
+        * According to Samba4, SEC_FILE_READ_ATTRIBUTE is always granted,
+        */
+       fsp->access_mask = access_mask | FILE_READ_ATTRIBUTES;
        fsp->print_file = False;
        fsp->modified = False;
        fsp->oplock_type = NO_OPLOCK;
        fsp->sent_oplock_break = NO_BREAK_SENT;
        fsp->is_directory = True;
-       fsp->is_stat = False;
        fsp->posix_open = (file_attributes & FILE_FLAG_POSIX_SEMANTICS) ? True : False;
 
        string_set(&fsp->fsp_name,fname);
 
+       mtimespec = get_mtimespec(psbuf);
+
        lck = get_share_mode_lock(talloc_tos(), fsp->file_id,
                                  conn->connectpath,
-                                 fname);
+                                 fname, &mtimespec);
 
        if (lck == NULL) {
                DEBUG(0, ("open_directory: Could not get share mode lock for %s\n", fname));
@@ -2236,7 +2497,7 @@ NTSTATUS open_directory(connection_struct *conn,
                return status;
        }
 
-       set_share_mode(lck, fsp, current_user.ut.uid, 0, NO_OPLOCK, True);
+       set_share_mode(lck, fsp, conn->server_info->utok.uid, 0, NO_OPLOCK);
 
        /* For directories the delete on close bit at open time seems
           always to be honored on close... See test 19 in Samba4 BASE-DELETE. */
@@ -2261,8 +2522,6 @@ NTSTATUS open_directory(connection_struct *conn,
                *pinfo = info;
        }
 
-       conn->num_files_open++;
-
        *result = fsp;
        return NT_STATUS_OK;
 }
@@ -2291,58 +2550,6 @@ NTSTATUS create_directory(connection_struct *conn, struct smb_request *req, cons
        return status;
 }
 
-/****************************************************************************
- Open a pseudo-file (no locking checks - a 'stat' open).
-****************************************************************************/
-
-NTSTATUS open_file_stat(connection_struct *conn, struct smb_request *req,
-                       const char *fname, SMB_STRUCT_STAT *psbuf,
-                       files_struct **result)
-{
-       files_struct *fsp = NULL;
-       NTSTATUS status;
-
-       if (!VALID_STAT(*psbuf)) {
-               return NT_STATUS_INVALID_PARAMETER;
-       }
-
-       /* Can't 'stat' open directories. */
-       if(S_ISDIR(psbuf->st_mode)) {
-               return NT_STATUS_FILE_IS_A_DIRECTORY;
-       }
-
-       status = file_new(conn, &fsp);
-       if(!NT_STATUS_IS_OK(status)) {
-               return status;
-       }
-
-       DEBUG(5,("open_file_stat: 'opening' file %s\n", fname));
-
-       /*
-        * Setup the files_struct for it.
-        */
-       
-       fsp->mode = psbuf->st_mode;
-       fsp->file_id = vfs_file_id_from_sbuf(conn, psbuf);
-       fsp->vuid = req ? req->vuid : UID_FIELD_INVALID;
-       fsp->file_pid = req ? req->smbpid : 0;
-       fsp->can_lock = False;
-       fsp->can_read = False;
-       fsp->can_write = False;
-       fsp->print_file = False;
-       fsp->modified = False;
-       fsp->oplock_type = NO_OPLOCK;
-       fsp->sent_oplock_break = NO_BREAK_SENT;
-       fsp->is_directory = False;
-       fsp->is_stat = True;
-       string_set(&fsp->fsp_name,fname);
-
-       conn->num_files_open++;
-
-       *result = fsp;
-       return NT_STATUS_OK;
-}
-
 /****************************************************************************
  Receive notification that one of our open files has been renamed by another
  smbd process.
@@ -2600,6 +2807,11 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                goto fail;
        }
 
+       if (create_options & NTCREATEX_OPTIONS_INVALID_PARAM_MASK) {
+               status = NT_STATUS_INVALID_PARAMETER;
+               goto fail;
+       }
+
        if (req == NULL) {
                oplock_request |= INTERNAL_OPEN_ONLY;
        }
@@ -2640,10 +2852,11 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
            && (create_disposition != FILE_CREATE)
            && (share_access & FILE_SHARE_DELETE)
            && (access_mask & DELETE_ACCESS)
-           && (((dos_mode(conn, fname, &sbuf) & FILE_ATTRIBUTE_READONLY)
-                && !lp_delete_readonly(SNUM(conn)))
-               || !can_delete_file_in_directory(conn, fname))) {
+           && (!(can_delete_file_in_directory(conn, fname) ||
+                can_access_file_acl(conn, fname, DELETE_ACCESS)))) {
                status = NT_STATUS_ACCESS_DENIED;
+               DEBUG(10,("create_file_unixpath: open file %s "
+                       "for delete ACCESS_DENIED\n", fname ));
                goto fail;
        }
 
@@ -2671,8 +2884,9 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                status = split_ntfs_stream_name(talloc_tos(), fname,
                                                &base, NULL);
                if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(10, ("split_ntfs_stream_name failed: %s\n",
-                                  nt_errstr(status)));
+                       DEBUG(10, ("create_file_unixpath: "
+                               "split_ntfs_stream_name failed: %s\n",
+                               nt_errstr(status)));
                        goto fail;
                }
 
@@ -2699,6 +2913,8 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                                   "%s\n", base, nt_errstr(status)));
                        goto fail;
                }
+               /* we don't need to low level fd */
+               fd_close(base_fsp);
        }
 
        /*
@@ -2735,13 +2951,52 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                 * Ordinary file case.
                 */
 
-               status = open_file_ntcreate(
-                       conn, req, fname, &sbuf, access_mask, share_access,
-                       create_disposition, create_options, file_attributes,
-                       oplock_request, &info, &fsp);
+               if (base_fsp) {
+                       /*
+                        * We're opening the stream element of a base_fsp
+                        * we already opened. We need to initialize
+                        * the fsp first, and set up the base_fsp pointer.
+                        */
+                       status = file_new(conn, &fsp);
+                       if(!NT_STATUS_IS_OK(status)) {
+                               goto fail;
+                       }
+
+                       fsp->base_fsp = base_fsp;
+
+                       status = open_file_ntcreate_internal(conn,
+                                               req,
+                                               fname,
+                                               &sbuf,
+                                               access_mask,
+                                               share_access,
+                                               create_disposition,
+                                               create_options,
+                                               file_attributes,
+                                               oplock_request,
+                                               &info,
+                                               fsp);
+
+                       if(!NT_STATUS_IS_OK(status)) {
+                               file_free(fsp);
+                               fsp = NULL;
+                       }
+               } else {
+                       status = open_file_ntcreate(
+                               conn, req, fname, &sbuf, access_mask, share_access,
+                               create_disposition, create_options, file_attributes,
+                               oplock_request, &info, &fsp);
+               }
 
                if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
 
+                       /* A stream open never opens a directory */
+
+                       if (base_fsp) {
+                               status = NT_STATUS_FILE_IS_A_DIRECTORY;
+                               goto fail;
+                       }
+
                        /*
                         * Fail the open if it was explicitly a non-directory
                         * file.
@@ -2765,6 +3020,8 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                goto fail;
        }
 
+       fsp->base_fsp = base_fsp;
+
        /*
         * According to the MS documentation, the only time the security
         * descriptor is applied to the opened file is iff we *created* the
@@ -2797,7 +3054,16 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
 
                fsp->access_mask = FILE_GENERIC_ALL;
 
-               status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
+               /* Convert all the generic bits. */
+               security_acl_map_generic(sd->dacl, &file_generic_mapping);
+               security_acl_map_generic(sd->sacl, &file_generic_mapping);
+
+               if (sec_info_sent & (OWNER_SECURITY_INFORMATION|
+                                       GROUP_SECURITY_INFORMATION|
+                                       DACL_SECURITY_INFORMATION|
+                                       SACL_SECURITY_INFORMATION)) {
+                       status = SMB_VFS_FSET_NT_ACL(fsp, sec_info_sent, sd);
+               }
 
                fsp->access_mask = saved_access_mask;
 
@@ -2840,17 +3106,7 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
                }
        }
 
-       DEBUG(10, ("create_file: info=%d\n", info));
-
-       /*
-        * Set fsp->base_fsp late enough that we can't "goto fail" anymore. In
-        * the fail: branch we call close_file(fsp, ERROR_CLOSE) which would
-        * also close fsp->base_fsp which we have to also do explicitly in
-        * this routine here, as not in all "goto fail:" we have the fsp set
-        * up already to be initialized with the base_fsp.
-        */
-
-       fsp->base_fsp = base_fsp;
+       DEBUG(10, ("create_file_unixpath: info=%d\n", info));
 
        *result = fsp;
        if (pinfo != NULL) {
@@ -2867,9 +3123,16 @@ NTSTATUS create_file_unixpath(connection_struct *conn,
        return NT_STATUS_OK;
 
  fail:
-       DEBUG(10, ("create_file: %s\n", nt_errstr(status)));
+       DEBUG(10, ("create_file_unixpath: %s\n", nt_errstr(status)));
 
        if (fsp != NULL) {
+               if (base_fsp && fsp->base_fsp == base_fsp) {
+                       /*
+                        * The close_file below will close
+                        * fsp->base_fsp.
+                        */
+                       base_fsp = NULL;
+               }
                close_file(fsp, ERROR_CLOSE);
                fsp = NULL;
        }
@@ -2941,7 +3204,8 @@ NTSTATUS create_file(connection_struct *conn,
                         * Check to see if this is a mac fork of some kind.
                         */
 
-                       if (is_ntfs_stream_name(fname)) {
+                       if ((conn->fs_capabilities & FILE_NAMED_STREAMS) &&
+                                       is_ntfs_stream_name(fname)) {
                                status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
                                goto fail;
                        }
@@ -3028,16 +3292,21 @@ NTSTATUS create_file(connection_struct *conn,
                         * also tries a QUERY_FILE_INFO on the file and then
                         * close it
                         */
-                       status = open_fake_file(conn, fake_file_type, fname,
+                       status = open_fake_file(conn, req->vuid,
+                                               fake_file_type, fname,
                                                access_mask, &fsp);
                        if (!NT_STATUS_IS_OK(status)) {
                                goto fail;
                        }
 
-                       SET_STAT_INVALID(sbuf);
-
+                       ZERO_STRUCT(sbuf);
                        goto done;
                }
+
+               if (!(conn->fs_capabilities & FILE_NAMED_STREAMS)) {
+                       status = NT_STATUS_OBJECT_PATH_NOT_FOUND;
+                       goto fail;
+               }
        }
 
        if ((req != NULL) && (req->flags2 & FLAGS2_DFS_PATHNAMES)) {
@@ -3080,6 +3349,8 @@ NTSTATUS create_file(connection_struct *conn,
                fname = converted_fname;
        }
 
+       TALLOC_FREE(case_state);
+
        /* All file access must go through check_name() */
 
        status = check_name(conn, fname);