smbd: Add some structure protection for durable reconnect
[samba.git] / source3 / smbd / durable.c
index 15d70058c6e2ea11a02f513af26b63b9d54282cc..1f6113e4cc9d2953250131a01d194615d7e6a645 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"
@@ -121,7 +122,6 @@ NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
        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,7 +169,7 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
                return NT_STATUS_INVALID_PARAMETER;
        }
 
-       if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
+       if ((fsp_lease_type(fsp) & SMB2_LEASE_HANDLE) == 0) {
                return NT_STATUS_NOT_SUPPORTED;
        }
 
@@ -194,10 +194,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);
        }
 
        /*
@@ -275,7 +272,6 @@ NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
        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);
@@ -306,30 +302,6 @@ static bool vfs_default_durable_reconnect_check_stat(
 {
        int ret;
 
-       if (cookie_st->st_ex_dev != fsp_st->st_ex_dev) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         name,
-                         "st_ex_dev",
-                         (unsigned long long)cookie_st->st_ex_dev,
-                         (unsigned long long)fsp_st->st_ex_dev));
-               return false;
-       }
-
-       if (cookie_st->st_ex_ino != fsp_st->st_ex_ino) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         name,
-                         "st_ex_ino",
-                         (unsigned long long)cookie_st->st_ex_ino,
-                         (unsigned long long)fsp_st->st_ex_ino));
-               return false;
-       }
-
        if (cookie_st->st_ex_mode != fsp_st->st_ex_mode) {
                DEBUG(1, ("vfs_default_durable_reconnect (%s): "
                          "stat_ex.%s differs: "
@@ -536,18 +508,6 @@ static bool vfs_default_durable_reconnect_check_stat(
                return false;
        }
 
-       if (cookie_st->vfs_private != fsp_st->vfs_private) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         name,
-                         "vfs_private",
-                         (unsigned long long)cookie_st->vfs_private,
-                         (unsigned long long)fsp_st->vfs_private));
-               return false;
-       }
-
        return true;
 }
 
@@ -586,10 +546,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;
@@ -612,8 +573,11 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        }
 
        /* Create an smb_filename with stream_name == NULL. */
-       smb_fname = synthetic_smb_fname(talloc_tos(), cookie.base_name,
-                                       NULL, NULL);
+       smb_fname = synthetic_smb_fname(talloc_tos(),
+                                       cookie.base_name,
+                                       NULL,
+                                       NULL,
+                                       0);
        if (smb_fname == NULL) {
                return NT_STATUS_NO_MEMORY;
        }
@@ -717,6 +681,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        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->fnum = op->local_id;
 
        /*
         * TODO:
@@ -737,6 +702,32 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
        fsp->aio_write_behind = false;
        fsp->oplock_type = e->op_type;
 
+       if (fsp->oplock_type == LEASE_OPLOCK) {
+               struct share_mode_lease *l = &lck->data->leases[e->lease_idx];
+               struct smb2_lease_key key;
+
+               key.data[0] = l->lease_key.data[0];
+               key.data[1] = l->lease_key.data[1];
+
+               fsp->lease = find_fsp_lease(fsp, &key, l);
+               if (fsp->lease == NULL) {
+                       TALLOC_FREE(lck);
+                       fsp_free(fsp);
+                       return NT_STATUS_NO_MEMORY;
+               }
+
+               /*
+                * Ensure the existing client guid matches the
+                * stored one in the share_mode_lease.
+                */
+               if (!GUID_equal(fsp_client_guid(fsp),
+                               &l->client_guid)) {
+                       TALLOC_FREE(lck);
+                       fsp_free(fsp);
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               }
+       }
+
        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;
@@ -864,7 +855,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
-       status = set_file_oplock(fsp, fsp->oplock_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)));