smbd: add twrp arg to synthetic_smb_fname()
[amitay/samba.git] / source3 / smbd / durable.c
index 80392e2c6dbbdd30eefe2404e437172265de209d..de4f457b1d2e8f7c354e8916321566e599e8be36 100644 (file)
@@ -30,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,
@@ -69,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;
        }
 
@@ -100,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;
@@ -117,11 +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;
 
        ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
                        (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -177,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;
        }
 
@@ -205,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);
                }
@@ -250,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;
@@ -267,11 +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;
 
        ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
                        (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
@@ -446,17 +452,15 @@ static bool vfs_default_durable_reconnect_check_stat(
                return false;
        }
 
-       if (cookie_st->st_ex_calculated_birthtime !=
-           fsp_st->st_ex_calculated_birthtime)
-       {
+       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_calculated_birthtime,
-                         (unsigned long long)fsp_st->st_ex_calculated_birthtime));
+                         (unsigned long long)cookie_st->st_ex_iflags,
+                         (unsigned long long)fsp_st->st_ex_iflags));
                return false;
        }
 
@@ -496,21 +500,25 @@ static bool vfs_default_durable_reconnect_check_stat(
                return false;
        }
 
-       if (cookie_st->st_ex_mask != fsp_st->st_ex_mask) {
-               DEBUG(1, ("vfs_default_durable_reconnect (%s): "
-                         "stat_ex.%s differs: "
-                         "cookie:%llu != stat:%llu, "
-                         "denying durable reconnect\n",
-                         name,
-                         "st_ex_mask",
-                         (unsigned long long)cookie_st->st_ex_mask,
-                         (unsigned long long)fsp_st->st_ex_mask));
-               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,
@@ -519,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;
@@ -546,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;
@@ -576,6 +587,7 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                                        cookie.base_name,
                                        NULL,
                                        NULL,
+                                       0,
                                        0);
        if (smb_fname == NULL) {
                return NT_STATUS_NO_MEMORY;
@@ -610,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"));
@@ -638,22 +645,22 @@ 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;
        }
@@ -670,69 +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?
         */
-       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) {
-               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;
-               }
+               uint32_t current_state;
+               uint16_t lease_version, epoch;
 
                /*
                 * Ensure the existing client guid matches the
-                * stored one in the share_mode_lease.
+                * stored one in the share_mode_entry.
                 */
                if (!GUID_equal(fsp_client_guid(fsp),
-                               &l->client_guid)) {
+                               &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)) {
@@ -747,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) {
@@ -766,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;
        }
 
@@ -838,6 +876,8 @@ NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
        }
 
+       (void)dos_mode(fsp->conn, fsp->fsp_name);
+
        ok = vfs_default_durable_reconnect_check_stat(&cookie.stat_info,
                                                      &fsp->fsp_name->st,
                                                      fsp_str_dbg(fsp));