s3:vfs_default: add basic support for durable handle request and reconnect
authorMichael Adam <obnox@samba.org>
Fri, 8 Jun 2012 15:54:19 +0000 (17:54 +0200)
committerStefan Metzmacher <metze@samba.org>
Sat, 8 Sep 2012 17:48:20 +0000 (19:48 +0200)
We only grant durable handles for CIFS/SMB2 only access,
that means "kernel oplocks", "kernel share modes" and "posix locking"
need to be set to "no".

For now we also don't grant durable handles if delete on close
is active on the handle.

Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
Pair-Programmed-With: Volker Lendecke <vl@samba.org>

source3/Makefile.in
source3/librpc/idl/open_files.idl
source3/modules/vfs_default.c
source3/smbd/durable.c [new file with mode: 0644]
source3/smbd/proto.h
source3/wscript_build

index b448c02bfb8fb125e3d3da1bfd405750f69b8161..2ad8eccdb2ae9751da022bd67a9559dd0560c04b 100644 (file)
@@ -984,6 +984,7 @@ SMBD_OBJ_SRV = smbd/server_reload.o \
               smbd/smbXsrv_session.o \
               smbd/smbXsrv_tcon.o \
               smbd/smbXsrv_open.o \
+              smbd/durable.o \
               $(MANGLE_OBJ) @VFS_STATIC@
 
 SMBD_OBJ_BASE = $(PARAM_WITHOUT_REG_OBJ) $(SMBD_OBJ_SRV) $(LIBSMB_OBJ) \
index 98e1c32db088667daf3c1b2568a1e76333c50eb1..eb0dfa08aee57615661a94244ff5881698b8097a 100644 (file)
@@ -46,4 +46,20 @@ interface open_files
                uint8 modified;
                [ignore] db_record *record;
        } share_mode_data;
+
+       /* these are 0x30 (48) characters */
+       const string VFS_DEFAULT_DURABLE_COOKIE_MAGIC =
+               "VFS_DEFAULT_DURABLE_COOKIE_MAGIC                ";
+       const uint32 VFS_DEFAULT_DURABLE_COOKIE_VERSION = 0;
+
+       typedef [public] struct {
+               [value(VFS_DEFAULT_DURABLE_COOKIE_MAGIC),charset(DOS)] uint8 magic[0x30];
+               [value(VFS_DEFAULT_DURABLE_COOKIE_VERSION)] uint32 version;
+               boolean8 allow_reconnect;
+               file_id id;
+               [string,charset(UTF8)] char *servicepath;
+               [string,charset(UTF8)] char *base_name;
+               hyper initial_allocation_size;
+               hyper position_information;
+       } vfs_default_durable_cookie;
 }
index 427e3af9ca3a9dee250738306dc92fbca8588596..8392feb8c43261e5f8939ef600654d37b00b672f 100644 (file)
@@ -2232,7 +2232,7 @@ static NTSTATUS vfswrap_durable_cookie(struct vfs_handle_struct *handle,
                                       TALLOC_CTX *mem_ctx,
                                       DATA_BLOB *cookie)
 {
-       return NT_STATUS_NOT_SUPPORTED;
+       return vfs_default_durable_cookie(fsp, mem_ctx, cookie);
 }
 
 static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
@@ -2241,7 +2241,8 @@ static NTSTATUS vfswrap_durable_disconnect(struct vfs_handle_struct *handle,
                                           TALLOC_CTX *mem_ctx,
                                           DATA_BLOB *new_cookie)
 {
-       return NT_STATUS_NOT_SUPPORTED;
+       return vfs_default_durable_disconnect(fsp, old_cookie, mem_ctx,
+                                             new_cookie);
 }
 
 static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
@@ -2252,7 +2253,9 @@ static NTSTATUS vfswrap_durable_reconnect(struct vfs_handle_struct *handle,
                                          struct files_struct **fsp,
                                          DATA_BLOB *new_cookie)
 {
-       return NT_STATUS_NOT_SUPPORTED;
+       return vfs_default_durable_reconnect(handle->conn, smb1req, op,
+                                            old_cookie, mem_ctx,
+                                            fsp, new_cookie);
 }
 
 static struct vfs_fn_pointers vfs_default_fns = {
diff --git a/source3/smbd/durable.c b/source3/smbd/durable.c
new file mode 100644 (file)
index 0000000..5953e1b
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+   Unix SMB/CIFS implementation.
+   Durable Handle default VFS implementation
+
+   Copyright (C) Stefan Metzmacher 2012
+   Copyright (C) Michael Adam 2012
+   Copyright (C) Volker Lendecke 2012
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "includes.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
+#include "smbd/globals.h"
+#include "libcli/security/security.h"
+#include "messages.h"
+#include "librpc/gen_ndr/ndr_open_files.h"
+#include "serverid.h"
+#include "fake_file.h"
+
+NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
+                                   TALLOC_CTX *mem_ctx,
+                                   DATA_BLOB *cookie_blob)
+{
+       struct connection_struct *conn = fsp->conn;
+       enum ndr_err_code ndr_err;
+       struct vfs_default_durable_cookie cookie;
+
+       if (!lp_durable_handles(SNUM(conn))) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (lp_kernel_share_modes(SNUM(conn))) {
+               /*
+                * We do not support durable handles
+                * if kernel share modes (flocks) are used
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (lp_kernel_oplocks(SNUM(conn))) {
+               /*
+                * We do not support durable handles
+                * if kernel oplocks are used
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if ((fsp->current_lock_count > 0) &&
+           lp_posix_locking(fsp->conn->params))
+       {
+               /*
+                * We do not support durable handles
+                * if the handle has posix locks.
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (fsp->is_directory) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (fsp->fh->fd == -1) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (is_ntfs_stream_smb_fname(fsp->fsp_name)) {
+               /*
+                * We do not support durable handles
+                * on streams for now.
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (is_fake_file(fsp->fsp_name)) {
+               /*
+                * We do not support durable handles
+                * on fake files.
+                */
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       ZERO_STRUCT(cookie);
+       cookie.allow_reconnect = false;
+       cookie.id = fsp->file_id;
+       cookie.servicepath = conn->connectpath;
+       cookie.base_name = fsp->fsp_name->base_name;
+       cookie.initial_allocation_size = fsp->initial_allocation_size;
+       cookie.position_information = fsp->fh->position_information;
+
+       ndr_err = ndr_push_struct_blob(cookie_blob, mem_ctx, &cookie,
+                       (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
+               return status;
+       }
+
+       return NT_STATUS_OK;
+}
+
+NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
+                                       const DATA_BLOB old_cookie,
+                                       TALLOC_CTX *mem_ctx,
+                                       DATA_BLOB *new_cookie)
+{
+       struct connection_struct *conn = fsp->conn;
+       NTSTATUS status;
+       enum ndr_err_code ndr_err;
+       struct vfs_default_durable_cookie cookie;
+       DATA_BLOB new_cookie_blob = data_blob_null;
+       struct share_mode_lock *lck;
+       bool ok;
+
+       *new_cookie = data_blob_null;
+
+       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);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
+               return status;
+       }
+
+       if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!file_id_equal(&fsp->file_id, &cookie.id)) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!BATCH_OPLOCK_TYPE(fsp->oplock_type)) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (fsp->num_pending_break_messages > 0) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       /*
+        * For now let it be simple and do not keep
+        * delete on close files durable open
+        */
+       if (fsp->initial_delete_on_close) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       if (fsp->delete_on_close) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (!VALID_STAT(fsp->fsp_name->st)) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       if (!S_ISREG(fsp->fsp_name->st.st_ex_mode)) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       /*
+        * The above checks are done in mark_share_mode_disconnected() too
+        * but we want to avoid getting the lock if possible
+        */
+       lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
+       if (lck != NULL) {
+               ok = mark_share_mode_disconnected(lck, fsp);
+               if (!ok) {
+                       TALLOC_FREE(lck);
+               }
+       }
+       if (lck != NULL) {
+               ok = brl_mark_disconnected(fsp);
+               if (!ok) {
+                       TALLOC_FREE(lck);
+               }
+       }
+       if (lck == NULL) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+       TALLOC_FREE(lck);
+
+       ZERO_STRUCT(cookie);
+       cookie.allow_reconnect = true;
+       cookie.id = fsp->file_id;
+       cookie.servicepath = conn->connectpath;
+       cookie.base_name = fsp->fsp_name->base_name;
+       cookie.initial_allocation_size = fsp->initial_allocation_size;
+       cookie.position_information = fsp->fh->position_information;
+
+       ndr_err = ndr_push_struct_blob(&new_cookie_blob, mem_ctx, &cookie,
+                       (ndr_push_flags_fn_t)ndr_push_vfs_default_durable_cookie);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
+               return status;
+       }
+
+       status = fd_close(fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               data_blob_free(&new_cookie_blob);
+               return status;
+       }
+
+       *new_cookie = new_cookie_blob;
+       return NT_STATUS_OK;
+}
+
+NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
+                                      struct smb_request *smb1req,
+                                      struct smbXsrv_open *op,
+                                      const DATA_BLOB old_cookie,
+                                      TALLOC_CTX *mem_ctx,
+                                      files_struct **result,
+                                      DATA_BLOB *new_cookie)
+{
+       struct share_mode_lock *lck;
+       struct share_mode_entry *e;
+       struct files_struct *fsp = NULL;
+       NTSTATUS status;
+       bool ok;
+       int ret;
+       int flags;
+       struct file_id file_id;
+       struct smb_filename *smb_fname = NULL;
+       enum ndr_err_code ndr_err;
+       struct vfs_default_durable_cookie cookie;
+       DATA_BLOB new_cookie_blob = data_blob_null;
+
+       *result = NULL;
+       *new_cookie = data_blob_null;
+
+       if (!lp_durable_handles(SNUM(conn))) {
+               return NT_STATUS_NOT_SUPPORTED;
+       }
+
+       /*
+        * the checks for kernel oplocks
+        * and similar things are done
+        * in the vfs_default_durable_cookie()
+        * 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);
+       if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+               status = ndr_map_error2ntstatus(ndr_err);
+               return status;
+       }
+
+       if (strcmp(cookie.magic, VFS_DEFAULT_DURABLE_COOKIE_MAGIC) != 0) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (cookie.version != VFS_DEFAULT_DURABLE_COOKIE_VERSION) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+
+       if (!cookie.allow_reconnect) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       if (strcmp(cookie.servicepath, conn->connectpath) != 0) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       /* 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;
+       }
+
+       ret = SMB_VFS_LSTAT(conn, smb_fname);
+       if (ret == -1) {
+               status = map_nt_error_from_unix_common(errno);
+               DEBUG(1, ("Unable to lstat stream: %s => %s\n",
+                         smb_fname_str_dbg(smb_fname),
+                         nt_errstr(status)));
+               return status;
+       }
+
+       if (!S_ISREG(smb_fname->st.st_ex_mode)) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       file_id = vfs_file_id_from_sbuf(conn, &smb_fname->st);
+       if (!file_id_equal(&cookie.id, &file_id)) {
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       /*
+        * 1. check entry in locking.tdb
+        */
+
+       lck = get_existing_share_mode_lock(mem_ctx, file_id);
+       if (lck == NULL) {
+               DEBUG(5, ("vfs_default_durable_reconnect: share-mode lock "
+                          "not obtained from db\n"));
+               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"));
+               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"));
+               TALLOC_FREE(lck);
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       e = &lck->data->share_modes[0];
+
+       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"));
+               TALLOC_FREE(lck);
+               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));
+               TALLOC_FREE(lck);
+               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+       }
+
+       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))));
+               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
+        */
+
+       status = fsp_new(conn, conn, &fsp);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0, ("vfs_default_durable_reconnect: failed to create "
+                         "new fsp: %s\n", nt_errstr(status)));
+               TALLOC_FREE(lck);
+               return status;
+       }
+
+       fsp->fh->private_options = e->private_options;
+       fsp->fh->gen_id = smbXsrv_open_hash(op);
+       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);
+
+       /*
+        * 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;
+       /*
+        * no durables for directories
+        */
+       fsp->is_directory = false;
+       /*
+        * For normal files, can_lock == !is_directory
+        */
+       fsp->can_lock = true;
+       /*
+        * We do not support aio write behind for smb2
+        */
+       fsp->aio_write_behind = false;
+       fsp->oplock_type = e->op_type;
+
+       fsp->initial_allocation_size = cookie.initial_allocation_size;
+       fsp->fh->position_information = cookie.position_information;
+
+       status = fsp_set_smb_fname(fsp, smb_fname);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(lck);
+               fsp_free(fsp);
+               DEBUG(0, ("vfs_default_durable_reconnect: "
+                         "fsp_set_smb_fname failed: %s\n",
+                         nt_errstr(status)));
+               return status;
+       }
+
+       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 = brl_reconnect_disconnected(fsp);
+       if (!ok) {
+               status = NT_STATUS_INTERNAL_ERROR;
+               DEBUG(1, ("vfs_default_durable_reconnect: "
+                         "failed to reopen brlocks: %s\n",
+                         nt_errstr(status)));
+               TALLOC_FREE(lck);
+               op->compat = NULL;
+               fsp_free(fsp);
+               return status;
+       }
+
+       /*
+        * TODO: properly calculate open flags
+        */
+       if (fsp->can_write && fsp->can_read) {
+               flags = O_RDWR;
+       } else if (fsp->can_write) {
+               flags = O_WRONLY;
+       } else if (fsp->can_read) {
+               flags = O_RDONLY;
+       }
+
+       status = fd_open(conn, fsp, flags, 0 /* mode */);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(lck);
+               DEBUG(1, ("vfs_default_durable_reconnect: failed to open "
+                         "file: %s\n", nt_errstr(status)));
+               op->compat = NULL;
+               fsp_free(fsp);
+               return status;
+       }
+
+       ret = SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st);
+       if (ret == -1) {
+               status = map_nt_error_from_unix_common(errno);
+               DEBUG(1, ("Unable to fstat stream: %s => %s\n",
+                         smb_fname_str_dbg(smb_fname),
+                         nt_errstr(status)));
+               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 status;
+
+       }
+
+       if (!S_ISREG(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;
+       }
+
+       file_id = vfs_file_id_from_sbuf(conn, &fsp->fsp_name->st);
+       if (!file_id_equal(&cookie.id, &file_id)) {
+               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;
+       }
+
+       status = set_file_oplock(fsp, e->op_type);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(1, ("vfs_default_durable_reconnect failed to set oplock "
+                         "after opening file: %s\n", nt_errstr(status)));
+               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 status;
+       }
+
+       status = vfs_default_durable_cookie(fsp, mem_ctx, &new_cookie_blob);
+       if (!NT_STATUS_IS_OK(status)) {
+               TALLOC_FREE(lck);
+               DEBUG(1, ("vfs_default_durable_reconnect: "
+                         "vfs_default_durable_cookie - %s\n",
+                         nt_errstr(status)));
+               op->compat = NULL;
+               fsp_free(fsp);
+               return status;
+       }
+
+       smb1req->chain_fsp = fsp;
+       smb1req->smb2req->compat_chain_fsp = fsp;
+
+       DEBUG(10, ("vfs_default_durable_reconnect: opened file '%s'\n",
+                  fsp_str_dbg(fsp)));
+
+       /*
+        * release the sharemode lock: this writes the changes
+        */
+       lck->data->modified = true;
+       TALLOC_FREE(lck);
+
+       *result = fsp;
+       *new_cookie = new_cookie_blob;
+
+       return NT_STATUS_OK;
+}
index ee8ebc01b8d57f8cf3978f617eda8d4cf0729253..a6aa862598b6d65bed48dbb92efcaefad1381267 100644 (file)
@@ -1162,4 +1162,21 @@ NTSTATUS vfs_streaminfo(connection_struct *conn,
 void *avahi_start_register(TALLOC_CTX *mem_ctx, struct tevent_context *ev,
                           uint16_t port);
 
+/* The following definitions come from smbd/smb2_create.c */
+
+NTSTATUS vfs_default_durable_cookie(struct files_struct *fsp,
+                                   TALLOC_CTX *mem_ctx,
+                                   DATA_BLOB *cookie_blob);
+NTSTATUS vfs_default_durable_disconnect(struct files_struct *fsp,
+                                       const DATA_BLOB old_cookie,
+                                       TALLOC_CTX *mem_ctx,
+                                       DATA_BLOB *new_cookie);
+NTSTATUS vfs_default_durable_reconnect(struct connection_struct *conn,
+                                      struct smb_request *smb1req,
+                                      struct smbXsrv_open *op,
+                                      const DATA_BLOB old_cookie,
+                                      TALLOC_CTX *mem_ctx,
+                                      files_struct **result,
+                                      DATA_BLOB *new_cookie);
+
 #endif /* _SMBD_PROTO_H_ */
index 88ad8ab0cb599e5ea3eff55c1ac45a739918df59..048875d66fc6d4740e6e8d58a0a16b7f520a4d74 100755 (executable)
@@ -381,6 +381,7 @@ SMBD_SRC_SRV = '''smbd/server_reload.c smbd/files.c smbd/connection.c
                smbd/smbXsrv_tcon.c
                smbd/smbXsrv_open.c
                smbd/server_exit.c
+               smbd/durable.c
                ${MANGLE_SRC}'''
 
 SMBD_SRC_BASE = '''${SMBD_SRC_SRV}