summaryrefslogtreecommitdiffstats
path: root/source3/smbd/smb2_create.c
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2014-10-28 15:31:46 -0700
committerJeremy Allison <jra@samba.org>2014-12-04 05:45:10 +0100
commite2d80a89d53fdd6794a344649c3c9728db93adce (patch)
treee43842ccd35530292c80db780403d41ad2f1d1f3 /source3/smbd/smb2_create.c
parent02f2684dd8e88f1c55bf69fa8b2aa27c1c404a3d (diff)
downloadsamba-e2d80a89d53fdd6794a344649c3c9728db93adce.tar.gz
samba-e2d80a89d53fdd6794a344649c3c9728db93adce.tar.xz
samba-e2d80a89d53fdd6794a344649c3c9728db93adce.zip
s3:smb2_create: support leases and pass them down to the VFS layer.
Pair-Programmed-With: Stefan Metzmacher <metze@samba.org> Signed-off-by: Volker Lendecke <vl@samba.org> Signed-off-by: Stefan Metzmacher <metze@samba.org> Reviewed-by: Jeremy Allison <jra@samba.org>
Diffstat (limited to 'source3/smbd/smb2_create.c')
-rw-r--r--source3/smbd/smb2_create.c91
1 files changed, 87 insertions, 4 deletions
diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c
index e96e84af09..e0eef43e5c 100644
--- a/source3/smbd/smb2_create.c
+++ b/source3/smbd/smb2_create.c
@@ -25,6 +25,7 @@
#include "smbd/globals.h"
#include "../libcli/smb/smb_common.h"
#include "../librpc/gen_ndr/ndr_security.h"
+#include "../librpc/gen_ndr/ndr_smb2_lease_struct.h"
#include "../lib/util/tevent_ntstatus.h"
#include "messages.h"
@@ -40,9 +41,7 @@ int map_smb2_oplock_levels_to_samba(uint8_t in_oplock_level)
case SMB2_OPLOCK_LEVEL_BATCH:
return BATCH_OPLOCK;
case SMB2_OPLOCK_LEVEL_LEASE:
- DEBUG(2,("map_smb2_oplock_levels_to_samba: "
- "LEASE_OPLOCK_REQUESTED\n"));
- return NO_OPLOCK;
+ return LEASE_OPLOCK;
default:
DEBUG(2,("map_smb2_oplock_levels_to_samba: "
"unknown level %u\n",
@@ -59,6 +58,8 @@ static uint8_t map_samba_oplock_levels_to_smb2(int oplock_type)
return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
} else if (oplock_type == LEVEL_II_OPLOCK) {
return SMB2_OPLOCK_LEVEL_II;
+ } else if (oplock_type == LEASE_OPLOCK) {
+ return SMB2_OPLOCK_LEVEL_LEASE;
} else {
return SMB2_OPLOCK_LEVEL_NONE;
}
@@ -368,6 +369,11 @@ static void smbd_smb2_request_create_done(struct tevent_req *tsubreq)
}
}
+static bool smb2_lease_key_valid(const struct smb2_lease_key *key)
+{
+ return ((key->data[0] != 0) || (key->data[1] != 0));
+}
+
static NTSTATUS smbd_smb2_create_durable_lease_check(
const char *requested_filename, const struct files_struct *fsp,
const struct smb2_lease *lease_ptr)
@@ -467,6 +473,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
struct smb2_create_blob *dh2c = NULL;
struct smb2_create_blob *dhnq = NULL;
struct smb2_create_blob *dh2q = NULL;
+ struct smb2_create_blob *rqls = NULL;
struct smbXsrv_open *op = NULL;
ZERO_STRUCT(out_context_blobs);
@@ -513,6 +520,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
SMB2_CREATE_TAG_DH2Q);
dh2c = smb2_create_blob_find(&in_context_blobs,
SMB2_CREATE_TAG_DH2C);
+ if (smb2req->xconn->smb2.server.capabilities & SMB2_CAP_LEASING) {
+ rqls = smb2_create_blob_find(&in_context_blobs,
+ SMB2_CREATE_TAG_RQLS);
+ }
if ((dhnc && dh2c) || (dhnc && dh2q) || (dh2c && dhnq) ||
(dh2q && dh2c))
@@ -552,6 +563,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
num_blobs_allowed = 1;
}
+ if (rqls != NULL) {
+ num_blobs_allowed += 1;
+ }
+
if (in_context_blobs.num_blobs != num_blobs_allowed) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
return tevent_req_post(req, ev);
@@ -584,6 +599,10 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
num_blobs_allowed = 1;
+ if (rqls != NULL) {
+ num_blobs_allowed += 1;
+ }
+
if (in_context_blobs.num_blobs != num_blobs_allowed) {
tevent_req_nterror(req, NT_STATUS_OBJECT_NAME_NOT_FOUND);
return tevent_req_post(req, ev);
@@ -650,7 +669,9 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
uint32_t durable_timeout_msec = 0;
bool do_durable_reconnect = false;
uint64_t persistent_id = 0;
+ struct smb2_lease lease;
struct smb2_lease *lease_ptr = NULL;
+ ssize_t lease_len = -1;
exta = smb2_create_blob_find(&in_context_blobs,
SMB2_CREATE_TAG_EXTA);
@@ -850,6 +871,34 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
}
}
+ if (rqls) {
+ lease_len = smb2_lease_pull(
+ rqls->data.data, rqls->data.length, &lease);
+ if (lease_len == -1) {
+ tevent_req_nterror(
+ req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+ lease_ptr = &lease;
+
+ if (DEBUGLEVEL >= 10) {
+ DEBUG(10, ("Got lease request size %d\n",
+ (int)lease_len));
+ NDR_PRINT_DEBUG(smb2_lease, lease_ptr);
+ }
+
+ if (!smb2_lease_key_valid(&lease.lease_key)) {
+ lease_ptr = NULL;
+ requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+ }
+
+ if ((smb2req->xconn->protocol < PROTOCOL_SMB3_00) &&
+ (lease.lease_version != 1)) {
+ DEBUG(10, ("v2 lease key only for SMB3\n"));
+ lease_ptr = NULL;
+ }
+ }
+
/* these are ignored for SMB2 */
in_create_options &= ~(0x10);/* NTCREATEX_OPTIONS_SYNC_ALERT */
in_create_options &= ~(0x20);/* NTCREATEX_OPTIONS_ASYNC_ALERT */
@@ -935,6 +984,14 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
} else {
struct smb_filename *smb_fname = NULL;
+ if (requested_oplock_level == SMB2_OPLOCK_LEVEL_LEASE) {
+ if (lease_ptr == NULL) {
+ requested_oplock_level = SMB2_OPLOCK_LEVEL_NONE;
+ }
+ } else {
+ lease_ptr = NULL;
+ }
+
/*
* For a DFS path the function parse_dfs_path()
* will do the path processing.
@@ -1005,7 +1062,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
in_create_options,
in_file_attributes,
map_smb2_oplock_levels_to_samba(requested_oplock_level),
- NULL,
+ lease_ptr,
allocation_size,
0, /* private_flags */
sec_desc,
@@ -1144,6 +1201,32 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
}
+
+ if ((rqls != NULL) && (result->oplock_type == LEASE_OPLOCK)) {
+ uint8_t buf[52];
+
+ lease = result->lease->lease;
+
+ lease_len = sizeof(buf);
+ if (lease.lease_version == 1) {
+ lease_len = 32;
+ }
+
+ if (!smb2_lease_push(&lease, buf, lease_len)) {
+ tevent_req_nterror(
+ req, NT_STATUS_INTERNAL_ERROR);
+ return tevent_req_post(req, ev);
+ }
+
+ status = smb2_create_blob_add(
+ state, &out_context_blobs,
+ SMB2_CREATE_TAG_RQLS,
+ data_blob_const(buf, lease_len));
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ }
}
smb2req->compat_chain_fsp = smb1req->chain_fsp;