diff options
author | Volker Lendecke <vl@samba.org> | 2014-10-28 15:31:46 -0700 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2014-12-04 05:45:10 +0100 |
commit | e2d80a89d53fdd6794a344649c3c9728db93adce (patch) | |
tree | e43842ccd35530292c80db780403d41ad2f1d1f3 /source3/smbd/smb2_create.c | |
parent | 02f2684dd8e88f1c55bf69fa8b2aa27c1c404a3d (diff) | |
download | samba-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.c | 91 |
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; |