smbd: add twrp arg to synthetic_smb_fname()
[amitay/samba.git] / source3 / smbd / durable.c
index 4c6ff67153c910403831f10940eecdc8d7d46e5e..de4f457b1d2e8f7c354e8916321566e599e8be36 100644 (file)
@@ -22,6 +22,7 @@
 
 #include "includes.h"
 #include "system/filesys.h"
+#include "lib/util/server_id.h"
 #include "smbd/smbd.h"
 #include "smbd/globals.h"
 #include "libcli/security/security.h"
@@ -29,6 +30,7 @@
 #include "librpc/gen_ndr/ndr_open_files.h"
 #include "serverid.h"
 #include "fake_file.h"
+#include "locking/leases_db.h"
 
 NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
                                    TALLOC_CTX *mem_ctx,
@@ -68,7 +70,7 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
                return NT_STATUS_NOT_SUPPORTED;
        }
 
-       if (fsp->is_directory) {
+       if (fsp->fsp_flags.is_directory) {
                return NT_STATUS_NOT_SUPPORTED;
        }
 
@@ -99,10 +101,13 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
        cookie.base_name = fsp->fsp_name->base_name;
        cookie.initial_allocation_size = fsp->initial_allocation_size;
        cookie.position_information = fsp->fh->position_information;
-       cookie.update_write_time_triggered = fsp->update_write_time_triggered;
-       cookie.update_write_time_on_close = fsp->update_write_time_on_close;
-       cookie.write_time_forced = fsp->write_time_forced;
-       cookie.close_write_time = fsp->close_write_time;
+       cookie.update_write_time_triggered =
+               fsp->fsp_flags.update_write_time_triggered;
+       cookie.update_write_time_on_close =
+               fsp->fsp_flags.update_write_time_on_close;
+       cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
+       cookie.close_write_time = full_timespec_to_nt_time(
+               &fsp->close_write_time);
 
        cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
        cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
@@ -116,12 +121,10 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
        cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
        cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
        cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
-       cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
+       cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
        cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
        cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
        cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
-       cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
-       cookie.stat_info.vfs_private = fsp->fsp_name->st.vfs_private;
 
        ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
                        (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -169,11 +172,7 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
-               return NT_STATUS_NOT_SUPPORTED;
-       }
-
-       if (fsp->num_pending_break_messages > 0) {
+       if ((fsp_lease_type(fsp) & SMB2_LEASE_HANDLE) == 0) {
                return NT_STATUS_NOT_SUPPORTED;
        }
 
@@ -181,10 +180,10 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
         * For now let it be simple and do not keep
         * delete on close files durable open
         */
-       if (fsp->initial_delete_on_close) {
+       if (fsp->fsp_flags.initial_delete_on_close) {
                return NT_STATUS_NOT_SUPPORTED;
        }
-       if (fsp->delete_on_close) {
+       if (fsp->fsp_flags.delete_on_close) {
                return NT_STATUS_NOT_SUPPORTED;
        }
 
@@ -198,10 +197,7 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
 
        /* Ensure any pending write time updates are done. */
        if (fsp->update_write_time_event) {
-               update_write_time_handler(fsp->conn->sconn->ev_ctx,
-                                       fsp->update_write_time_event,
-                                       timeval_current(),
-                                       (void *)fsp);
+               fsp_flush_write_time_update(fsp);
        }
 
        /*
@@ -212,19 +208,20 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
        if (lck != NULL) {
                struct smb_file_time ft;
 
-               ZERO_STRUCT(ft);
+               init_smb_file_time(&ft);
 
-               if (fsp->write_time_forced) {
-                       ft.mtime = lck->data->changed_write_time;
-               } else if (fsp->update_write_time_on_close) {
-                       if (null_timespec(fsp->close_write_time)) {
+               if (fsp->fsp_flags.write_time_forced) {
+                       ft.mtime = nt_time_to_full_timespec(
+                               lck->data->changed_write_time);
+               } else if (fsp->fsp_flags.update_write_time_on_close) {
+                       if (is_omit_timespec(&fsp->close_write_time)) {
                                ft.mtime = timespec_current();
                        } else {
                                ft.mtime = fsp->close_write_time;
                        }
                }
 
-               if (!null_timespec(ft.mtime)) {
+               if (!is_omit_timespec(&ft.mtime)) {
                        round_timespec(conn->ts_res, &ft.mtime);
                        file_ntimes(conn, fsp->fsp_name, &ft);
                }
@@ -257,10 +254,13 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
        cookie.base_name = fsp->fsp_name->base_name;
        cookie.initial_allocation_size = fsp->initial_allocation_size;
        cookie.position_information = fsp->fh->position_information;
-       cookie.update_write_time_triggered = fsp->update_write_time_triggered;
-       cookie.update_write_time_on_close = fsp->update_write_time_on_close;
-       cookie.write_time_forced = fsp->write_time_forced;
-       cookie.close_write_time = fsp->close_write_time;
+       cookie.update_write_time_triggered =
+               fsp->fsp_flags.update_write_time_triggered;
+       cookie.update_write_time_on_close =
+               fsp->fsp_flags.update_write_time_on_close;
+       cookie.write_time_forced = fsp->fsp_flags.write_time_forced;
+       cookie.close_write_time = full_timespec_to_nt_time(
+               &fsp->close_write_time);
 
        cookie.stat_info.st_ex_dev = fsp->fsp_name->st.st_ex_dev;
        cookie.stat_info.st_ex_ino = fsp->fsp_name->st.st_ex_ino;
@@ -274,12 +274,10 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
        cookie.stat_info.st_ex_mtime = fsp->fsp_name->st.st_ex_mtime;
        cookie.stat_info.st_ex_ctime = fsp->fsp_name->st.st_ex_ctime;
        cookie.stat_info.st_ex_btime = fsp->fsp_name->st.st_ex_btime;
-       cookie.stat_info.st_ex_calculated_birthtime = fsp->fsp_name->st.st_ex_calculated_birthtime;
+       cookie.stat_info.st_ex_iflags = fsp->fsp_name->st.st_ex_iflags;
        cookie.stat_info.st_ex_blksize = fsp->fsp_name->st.st_ex_blksize;
        cookie.stat_info.st_ex_blocks = fsp->fsp_name->st.st_ex_blocks;
        cookie.stat_info.st_ex_flags = fsp->fsp_name->st.st_ex_flags;
-       cookie.stat_info.st_ex_mask = fsp->fsp_name->st.st_ex_mask;
-       cookie.stat_info.vfs_private = fsp->fsp_name->st.vfs_private;
 
        ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
                        (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -298,6 +296,229 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
        return NT_STATUS_OK;
 }
 
+
+/**
+ * Check whether a cookie-stored struct info is the same
+ * as a given SMB_STRUCT_STAT, as coming with the fsp.
+ */
+static bool vfs_default_durable_reconnect_check_stat(
+                               struct vfs_default_durable_stat *cookie_st,
+                               SMB_STRUCT_STAT *fsp_st,
+                               const char *name)
+{
+       int ret;
+
+       if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_mode",
+                         (unsigned long long)cookie_st->st_ex_mode,
+                         (unsigned long long)fsp_st->st_ex_mode));
+               return false;
+       }
+
+       if (cookie_st->st_ex_nlink != fsp_st->st_ex_nlink) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_nlink",
+                         (unsigned long long)cookie_st->st_ex_nlink,
+                         (unsigned long long)fsp_st->st_ex_nlink));
+               return false;
+       }
+
+       if (cookie_st->st_ex_uid != fsp_st->st_ex_uid) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_uid",
+                         (unsigned long long)cookie_st->st_ex_uid,
+                         (unsigned long long)fsp_st->st_ex_uid));
+               return false;
+       }
+
+       if (cookie_st->st_ex_gid != fsp_st->st_ex_gid) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_gid",
+                         (unsigned long long)cookie_st->st_ex_gid,
+                         (unsigned long long)fsp_st->st_ex_gid));
+               return false;
+       }
+
+       if (cookie_st->st_ex_rdev != fsp_st->st_ex_rdev) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_rdev",
+                         (unsigned long long)cookie_st->st_ex_rdev,
+                         (unsigned long long)fsp_st->st_ex_rdev));
+               return false;
+       }
+
+       if (cookie_st->st_ex_size != fsp_st->st_ex_size) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_size",
+                         (unsigned long long)cookie_st->st_ex_size,
+                         (unsigned long long)fsp_st->st_ex_size));
+               return false;
+       }
+
+       ret = timespec_compare(&cookie_st->st_ex_atime,
+                              &fsp_st->st_ex_atime);
+       if (ret != 0) {
+               struct timeval tc, ts;
+               tc = convert_timespec_to_timeval(cookie_st->st_ex_atime);
+               ts = convert_timespec_to_timeval(fsp_st->st_ex_atime);
+
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:'%s' != stat:'%s', "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_atime",
+                         timeval_string(talloc_tos(), &tc, true),
+                         timeval_string(talloc_tos(), &ts, true)));
+               return false;
+       }
+
+       ret = timespec_compare(&cookie_st->st_ex_mtime,
+                              &fsp_st->st_ex_mtime);
+       if (ret != 0) {
+               struct timeval tc, ts;
+               tc = convert_timespec_to_timeval(cookie_st->st_ex_mtime);
+               ts = convert_timespec_to_timeval(fsp_st->st_ex_mtime);
+
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:'%s' != stat:'%s', "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_mtime",
+                         timeval_string(talloc_tos(), &tc, true),
+                         timeval_string(talloc_tos(), &ts, true)));
+               return false;
+       }
+
+       ret = timespec_compare(&cookie_st->st_ex_ctime,
+                              &fsp_st->st_ex_ctime);
+       if (ret != 0) {
+               struct timeval tc, ts;
+               tc = convert_timespec_to_timeval(cookie_st->st_ex_ctime);
+               ts = convert_timespec_to_timeval(fsp_st->st_ex_ctime);
+
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:'%s' != stat:'%s', "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_ctime",
+                         timeval_string(talloc_tos(), &tc, true),
+                         timeval_string(talloc_tos(), &ts, true)));
+               return false;
+       }
+
+       ret = timespec_compare(&cookie_st->st_ex_btime,
+                              &fsp_st->st_ex_btime);
+       if (ret != 0) {
+               struct timeval tc, ts;
+               tc = convert_timespec_to_timeval(cookie_st->st_ex_btime);
+               ts = convert_timespec_to_timeval(fsp_st->st_ex_btime);
+
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:'%s' != stat:'%s', "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_btime",
+                         timeval_string(talloc_tos(), &tc, true),
+                         timeval_string(talloc_tos(), &ts, true)));
+               return false;
+       }
+
+       if (cookie_st->st_ex_iflags != fsp_st->st_ex_iflags) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_calculated_birthtime",
+                         (unsigned long long)cookie_st->st_ex_iflags,
+                         (unsigned long long)fsp_st->st_ex_iflags));
+               return false;
+       }
+
+       if (cookie_st->st_ex_blksize != fsp_st->st_ex_blksize) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_blksize",
+                         (unsigned long long)cookie_st->st_ex_blksize,
+                         (unsigned long long)fsp_st->st_ex_blksize));
+               return false;
+       }
+
+       if (cookie_st->st_ex_blocks != fsp_st->st_ex_blocks) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_blocks",
+                         (unsigned long long)cookie_st->st_ex_blocks,
+                         (unsigned long long)fsp_st->st_ex_blocks));
+               return false;
+       }
+
+       if (cookie_st->st_ex_flags != fsp_st->st_ex_flags) {
+               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
+                         "stat_ex.%s differs: "
+                         "cookie:%llu != stat:%llu, "
+                         "denying durable reconnect\n",
+                         name,
+                         "st_ex_flags",
+                         (unsigned long long)cookie_st->st_ex_flags,
+                         (unsigned long long)fsp_st->st_ex_flags));
+               return false;
+       }
+
+       return true;
+}
+
+static bool durable_reconnect_fn(
+       struct share_mode_entry *e,
+       bool *modified,
+       void *private_data)
+{
+       struct share_mode_entry *dst_e = private_data;
+
+       if (dst_e->pid.pid != 0) {
+               DBG_INFO("Found more than one entry, invalidating previous\n");
+               dst_e->pid.pid = 0;
+               return true;    /* end the loop through share mode entries */
+       }
+       *dst_e = *e;
+       return false;           /* Look at potential other entries */
+}
+
 NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                                       struct smb_request *smb1req,
                                       struct smbXsrv_open *op,
@@ -306,8 +527,10 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                                       files_struct **result,
                                       DATA_BLOB *new_cookie)
 {
+       const struct loadparm_substitution *lp_sub =
+               loadparm_s3_global_substitution();
        struct share_mode_lock *lck;
-       struct share_mode_entry *e;
+       struct share_mode_entry e;
        struct files_struct *fsp = NULL;
        NTSTATUS status;
        bool ok;
@@ -333,10 +556,11 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
         * call below.
         */
 
-       ZERO_STRUCT(cookie);
-
-       ndr_err = ndr_pull_struct_blob(&old_cookie, talloc_tos(), &cookie,
-                       (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
+       ndr_err = ndr_pull_struct_blob_all(
+               &old_cookie,
+               talloc_tos(),
+               &cookie,
+               (ndr_pull_flags_fn_t)ndr_pull_vfs_default_durable_cookie);
        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
                status = ndr_map_error2ntstatus(ndr_err);
                return status;
@@ -359,12 +583,14 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        }
 
        /* Create an smb_filename with stream_name == NULL. */
-       status = create_synthetic_smb_fname(talloc_tos(),
-                                           cookie.base_name,
-                                           NULL, NULL,
-                                           &smb_fname);
-       if (!NT_STATUS_IS_OK(status)) {
-               return status;
+       smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       cookie.base_name,
+                                       NULL,
+                                       NULL,
+                                       0,
+                                       0);
+       if (smb_fname == NULL) {
+               return NT_STATUS_NO_MEMORY;
        }
 
        ret = SMB_VFS_LSTAT(conn, smb_fname);
@@ -396,27 +622,22 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if (lck->data->num_share_modes == 0) {
-               DEBUG(1, ("vfs_default_durable_reconnect: Error: no share-mode "
-                         "entry in existing share mode lock\n"));
+       e = (struct share_mode_entry) { .pid.pid = 0 };
+
+       ok = share_mode_forall_entries(lck, durable_reconnect_fn, &e);
+       if (!ok) {
+               DBG_WARNING("share_mode_forall_entries failed\n");
                TALLOC_FREE(lck);
                return NT_STATUS_INTERNAL_DB_ERROR;
        }
 
-       if (lck->data->num_share_modes > 1) {
-               /*
-                * It can't be durable if there is more than one handle
-                * on the file.
-                */
-               DEBUG(5, ("vfs_default_durable_reconnect: more than one "
-                         "share-mode entry - can not be durable\n"));
+       if (e.pid.pid == 0) {
+               DBG_WARNING("Did not find a unique valid share mode entry\n");
                TALLOC_FREE(lck);
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       e = &lck->data->share_modes[0];
-
-       if (!server_id_is_disconnected(&e->pid)) {
+       if (!server_id_is_disconnected(&e.pid)) {
                DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
                          "reconnect for handle that was not marked "
                          "disconnected (e.g. smbd or cluster node died)\n"));
@@ -424,40 +645,26 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if (e->share_file_id != op->global->open_persistent_id) {
-               DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
-                         "share_file_id changed %llu != %llu"
-                         "(e.g. another client had opened the file)\n",
-                         (unsigned long long)e->share_file_id,
-                         (unsigned long long)op->global->open_persistent_id));
+       if (e.share_file_id != op->global->open_persistent_id) {
+               DBG_INFO("denying durable "
+                        "share_file_id changed %"PRIu64" != %"PRIu64" "
+                        "(e.g. another client had opened the file)\n",
+                        e.share_file_id,
+                        op->global->open_persistent_id);
                TALLOC_FREE(lck);
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if ((e->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
+       if ((e.access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) &&
            !CAN_WRITE(conn))
        {
                DEBUG(5, ("vfs_default_durable_reconnect: denying durable "
                          "share[%s] is not writeable anymore\n",
-                         lp_servicename(talloc_tos(), SNUM(conn))));
+                         lp_servicename(talloc_tos(), lp_sub, SNUM(conn))));
                TALLOC_FREE(lck);
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       /*
-        * TODO:
-        * add scavenger timer functionality
-        *
-        * For now we always allow the reconnect
-        */
-#if 0
-       expire_time = op->global->disconnect_time;
-       expire_time += NTTIME_MAGIC(op->global->durable_timeout_msec);
-       if (expire < now) {
-               //TODO reopen and close before telling the client...
-       }
-#endif
-
        /*
         * 2. proceed with opening file
         */
@@ -470,44 +677,89 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return status;
        }
 
-       fsp->fh->private_options = e->private_options;
-       fsp->fh->gen_id = smbXsrv_open_hash(op);
+       fsp->fh->private_options = e.private_options;
        fsp->file_id = file_id;
        fsp->file_pid = smb1req->smbpid;
        fsp->vuid = smb1req->vuid;
-       fsp->open_time = e->time;
-       fsp->access_mask = e->access_mask;
-       fsp->share_access = e->share_access;
-       fsp->can_read = ((fsp->access_mask & (FILE_READ_DATA)) != 0);
-       fsp->can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
+       fsp->open_time = e.time;
+       fsp->access_mask = e.access_mask;
+       fsp->fsp_flags.can_read = ((fsp->access_mask & FILE_READ_DATA) != 0);
+       fsp->fsp_flags.can_write = ((fsp->access_mask & (FILE_WRITE_DATA|FILE_APPEND_DATA)) != 0);
+       fsp->fnum = op->local_id;
+       fsp_set_gen_id(fsp);
 
        /*
         * TODO:
         * Do we need to store the modified flag in the DB?
-        * How to handle update_write_time and friends
-        * during a disconnected client on a durable handle?
         */
-       fsp->modified = false;
+       fsp->fsp_flags.modified = false;
        /*
         * no durables for directories
         */
-       fsp->is_directory = false;
+       fsp->fsp_flags.is_directory = false;
        /*
         * For normal files, can_lock == !is_directory
         */
-       fsp->can_lock = true;
+       fsp->fsp_flags.can_lock = true;
        /*
         * We do not support aio write behind for smb2
         */
-       fsp->aio_write_behind = false;
-       fsp->oplock_type = e->op_type;
+       fsp->fsp_flags.aio_write_behind = false;
+       fsp->oplock_type = e.op_type;
+
+       if (fsp->oplock_type == LEASE_OPLOCK) {
+               uint32_t current_state;
+               uint16_t lease_version, epoch;
+
+               /*
+                * Ensure the existing client guid matches the
+                * stored one in the share_mode_entry.
+                */
+               if (!GUID_equal(fsp_client_guid(fsp),
+                               &e.client_guid)) {
+                       TALLOC_FREE(lck);
+                       fsp_free(fsp);
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               }
+
+               status = leases_db_get(
+                       &e.client_guid,
+                       &e.lease_key,
+                       &file_id,
+                       &current_state, /* current_state */
+                       NULL, /* breaking */
+                       NULL, /* breaking_to_requested */
+                       NULL, /* breaking_to_required */
+                       &lease_version, /* lease_version */
+                       &epoch); /* epoch */
+               if (!NT_STATUS_IS_OK(status)) {
+                       TALLOC_FREE(lck);
+                       fsp_free(fsp);
+                       return status;
+               }
+
+               fsp->lease = find_fsp_lease(
+                       fsp,
+                       &e.lease_key,
+                       current_state,
+                       lease_version,
+                       epoch);
+               if (fsp->lease == NULL) {
+                       TALLOC_FREE(lck);
+                       fsp_free(fsp);
+                       return NT_STATUS_NO_MEMORY;
+               }
+       }
 
        fsp->initial_allocation_size = cookie.initial_allocation_size;
        fsp->fh->position_information = cookie.position_information;
-       fsp->update_write_time_triggered = cookie.update_write_time_triggered;
-       fsp->update_write_time_on_close = cookie.update_write_time_on_close;
-       fsp->write_time_forced = cookie.write_time_forced;
-       fsp->close_write_time = cookie.close_write_time;
+       fsp->fsp_flags.update_write_time_triggered =
+               cookie.update_write_time_triggered;
+       fsp->fsp_flags.update_write_time_on_close =
+               cookie.update_write_time_on_close;
+       fsp->fsp_flags.write_time_forced = cookie.write_time_forced;
+       fsp->close_write_time = nt_time_to_full_timespec(
+               cookie.close_write_time);
 
        status = fsp_set_smb_fname(fsp, smb_fname);
        if (!NT_STATUS_IS_OK(status)) {
@@ -522,9 +774,20 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        op->compat = fsp;
        fsp->op = op;
 
-       e->pid = messaging_server_id(conn->sconn->msg_ctx);
-       e->op_mid = smb1req->mid;
-       e->share_file_id = fsp->fh->gen_id;
+       ok = reset_share_mode_entry(
+               lck,
+               e.pid,
+               e.share_file_id,
+               messaging_server_id(conn->sconn->msg_ctx),
+               smb1req->mid,
+               fsp->fh->gen_id);
+       if (!ok) {
+               DBG_DEBUG("Could not set new share_mode_entry values\n");
+               TALLOC_FREE(lck);
+               op->compat = NULL;
+               fsp_free(fsp);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
 
        ok = brl_reconnect_disconnected(fsp);
        if (!ok) {
@@ -541,11 +804,11 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        /*
         * TODO: properly calculate open flags
         */
-       if (fsp->can_write && fsp->can_read) {
+       if (fsp->fsp_flags.can_write && fsp->fsp_flags.can_read) {
                flags = O_RDWR;
-       } else if (fsp->can_write) {
+       } else if (fsp->fsp_flags.can_write) {
                flags = O_WRONLY;
-       } else if (fsp->can_read) {
+       } else if (fsp->fsp_flags.can_read) {
                flags = O_RDONLY;
        }
 
@@ -613,398 +876,12 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       if (cookie.stat_info.st_ex_dev != fsp->fsp_name->st.st_ex_dev) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_dev",
-                         (unsigned long long)cookie.stat_info.st_ex_dev,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_dev));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_ino != fsp->fsp_name->st.st_ex_ino) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_ino",
-                         (unsigned long long)cookie.stat_info.st_ex_ino,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_ino));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_mode != fsp->fsp_name->st.st_ex_mode) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_mode",
-                         (unsigned long long)cookie.stat_info.st_ex_mode,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_mode));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_nlink != fsp->fsp_name->st.st_ex_nlink) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_nlink",
-                         (unsigned long long)cookie.stat_info.st_ex_nlink,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_nlink));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_uid != fsp->fsp_name->st.st_ex_uid) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_uid",
-                         (unsigned long long)cookie.stat_info.st_ex_uid,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_uid));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_gid != fsp->fsp_name->st.st_ex_gid) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_gid",
-                         (unsigned long long)cookie.stat_info.st_ex_gid,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_gid));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_rdev != fsp->fsp_name->st.st_ex_rdev) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_rdev",
-                         (unsigned long long)cookie.stat_info.st_ex_rdev,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_rdev));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_size != fsp->fsp_name->st.st_ex_size) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_size",
-                         (unsigned long long)cookie.stat_info.st_ex_size,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_size));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       ret = timespec_compare(&cookie.stat_info.st_ex_atime,
-                              &fsp->fsp_name->st.st_ex_atime);
-       if (ret != 0) {
-               struct timeval tc, ts;
-               tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_atime);
-               ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_atime);
-
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:'%s' != stat:'%s', "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_atime",
-                         timeval_string(talloc_tos(), &tc, true),
-                         timeval_string(talloc_tos(), &ts, true)));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       ret = timespec_compare(&cookie.stat_info.st_ex_mtime,
-                              &fsp->fsp_name->st.st_ex_mtime);
-       if (ret != 0) {
-               struct timeval tc, ts;
-               tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_mtime);
-               ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_mtime);
-
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:'%s' != stat:'%s', "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_mtime",
-                         timeval_string(talloc_tos(), &tc, true),
-                         timeval_string(talloc_tos(), &ts, true)));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       ret = timespec_compare(&cookie.stat_info.st_ex_ctime,
-                              &fsp->fsp_name->st.st_ex_ctime);
-       if (ret != 0) {
-               struct timeval tc, ts;
-               tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_ctime);
-               ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_ctime);
+       (void)dos_mode(fsp->conn, fsp->fsp_name);
 
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:'%s' != stat:'%s', "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_ctime",
-                         timeval_string(talloc_tos(), &tc, true),
-                         timeval_string(talloc_tos(), &ts, true)));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       ret = timespec_compare(&cookie.stat_info.st_ex_btime,
-                              &fsp->fsp_name->st.st_ex_btime);
-       if (ret != 0) {
-               struct timeval tc, ts;
-               tc = convert_timespec_to_timeval(cookie.stat_info.st_ex_btime);
-               ts = convert_timespec_to_timeval(fsp->fsp_name->st.st_ex_btime);
-
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:'%s' != stat:'%s', "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_btime",
-                         timeval_string(talloc_tos(), &tc, true),
-                         timeval_string(talloc_tos(), &ts, true)));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_calculated_birthtime !=
-           fsp->fsp_name->st.st_ex_calculated_birthtime)
-       {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_calculated_birthtime",
-                         (unsigned long long)cookie.stat_info.st_ex_calculated_birthtime,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_calculated_birthtime));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_blksize != fsp->fsp_name->st.st_ex_blksize) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_blksize",
-                         (unsigned long long)cookie.stat_info.st_ex_blksize,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_blksize));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_blocks != fsp->fsp_name->st.st_ex_blocks) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_blocks",
-                         (unsigned long long)cookie.stat_info.st_ex_blocks,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_blocks));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_flags != fsp->fsp_name->st.st_ex_flags) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_flags",
-                         (unsigned long long)cookie.stat_info.st_ex_flags,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_flags));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.st_ex_mask != fsp->fsp_name->st.st_ex_mask) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "st_ex_mask",
-                         (unsigned long long)cookie.stat_info.st_ex_mask,
-                         (unsigned long long)fsp->fsp_name->st.st_ex_mask));
-               ret = SMB_VFS_CLOSE(fsp);
-               if (ret == -1) {
-                       DEBUG(0, ("vfs_default_durable_reconnect: "
-                                 "SMB_VFS_CLOSE failed (%s) - leaking file "
-                                 "descriptor\n", strerror(errno)));
-               }
-               TALLOC_FREE(lck);
-               op->compat = NULL;
-               fsp_free(fsp);
-               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
-       }
-
-       if (cookie.stat_info.vfs_private != fsp->fsp_name->st.vfs_private) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         fsp_str_dbg(fsp),
-                         "vfs_private",
-                         (unsigned long long)cookie.stat_info.vfs_private,
-                         (unsigned long long)fsp->fsp_name->st.vfs_private));
+       ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
+                                                     &fsp->fsp_name->st,
+                                                     fsp_str_dbg(fsp));
+       if (!ok) {
                ret = SMB_VFS_CLOSE(fsp);
                if (ret == -1) {
                        DEBUG(0, ("vfs_default_durable_reconnect: "
@@ -1017,7 +894,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       status = set_file_oplock(fsp, e->op_type);
+       status = set_file_oplock(fsp);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
                          "after opening file: %s\n", nt_errstr(status)));