From 6b2f19a5e6e8b3eb2a44cd24408ba4f27cfb8745 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 27 Nov 2014 18:34:56 +0100 Subject: [PATCH] s3:open_files.idl: add data structures for SMB2.1 and SMB3.0 leases. Pair-Programmed-With: Volker Lendecke Signed-off-by: Volker Lendecke Signed-off-by: Stefan Metzmacher --- source3/include/smb.h | 1 + source3/librpc/idl/open_files.idl | 36 +++++++++++++++++++++++++++++++ source3/librpc/wscript_build | 2 +- source3/locking/locking.c | 17 +++++++++++++-- source3/locking/proto.h | 5 +++-- source3/locking/share_mode_lock.c | 12 ++++++++++- source3/smbd/open.c | 10 ++++++--- source3/utils/status.c | 9 ++++++++ 8 files changed, 83 insertions(+), 9 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index 53d3edc60f2f..a6589dbac7c6 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -577,6 +577,7 @@ enum remote_arch_types {RA_UNKNOWN, RA_WFWG, RA_OS2, RA_WIN95, RA_WINNT, #define EXCLUSIVE_OPLOCK OPLOCK_EXCLUSIVE #define BATCH_OPLOCK OPLOCK_BATCH #define LEVEL_II_OPLOCK OPLOCK_LEVEL_II +#define LEASE_OPLOCK 0x100 /* The following are Samba-private. */ #define INTERNAL_OPEN_ONLY 0x8 diff --git a/source3/librpc/idl/open_files.idl b/source3/librpc/idl/open_files.idl index 42783018e29a..0a9d5fd105e0 100644 --- a/source3/librpc/idl/open_files.idl +++ b/source3/librpc/idl/open_files.idl @@ -3,6 +3,8 @@ import "server_id.idl"; import "security.idl"; import "file_id.idl"; +import "smb2_lease_struct.idl"; +import "misc.idl"; [ pointer_default(unique) @@ -10,10 +12,41 @@ import "file_id.idl"; interface open_files { + typedef [public,flag(NDR_PAHEX)] struct { + GUID client_guid; + smb2_lease_key lease_key; + smb2_lease_state current_state; + /* + * 'breaking' indicates that we're waiting + * for a lease break ack from the client + * and breaking_to_requested and breaking_to_required + * have a meaning. + * + * breaking_to_requested is the value already sent to + * the client, the client needs to ack to this (or less). + * + * breaking_to_required is the internal value that needs to + * be reached before we can reset breaking = false, this + * may requires multiple roundtrips to the client, e.g. + * when the lease broken to a more reduced value, while + * the lease break is still in progress. + * + * The following can be assumed (if breaking == true): + * + * current_state > breaking_to_requested >= breaking_to_required + */ + boolean8 breaking; + smb2_lease_state breaking_to_requested; + smb2_lease_state breaking_to_required; + uint16 lease_version; + uint16 epoch; + } share_mode_lease; + typedef [public] struct { server_id pid; hyper op_mid; uint16 op_type; + uint32 lease_idx; uint32 access_mask; uint32 share_access; uint32 private_options; @@ -29,6 +62,7 @@ interface open_files * to store this share_mode_entry on disk. */ [skip] boolean8 stale; + [skip] share_mode_lease *lease; } share_mode_entry; typedef [public] struct { @@ -43,6 +77,8 @@ interface open_files [string,charset(UTF8)] char *stream_name; uint32 num_share_modes; [size_is(num_share_modes)] share_mode_entry share_modes[]; + uint32 num_leases; + [size_is(num_leases)] share_mode_lease leases[]; uint32 num_delete_tokens; [size_is(num_delete_tokens)] delete_token delete_tokens[]; timespec old_write_time; diff --git a/source3/librpc/wscript_build b/source3/librpc/wscript_build index 38d9a81a55f2..5c83cf2e13d4 100644 --- a/source3/librpc/wscript_build +++ b/source3/librpc/wscript_build @@ -17,7 +17,7 @@ bld.SAMBA3_SUBSYSTEM('NDR_MESSAGING', bld.SAMBA3_SUBSYSTEM('NDR_OPEN_FILES', source='gen_ndr/ndr_open_files.c', - public_deps='ndr NDR_SERVER_ID NDR_FILE_ID NDR_SECURITY' + public_deps='ndr NDR_SERVER_ID NDR_FILE_ID NDR_SECURITY NDR_SMB2_LEASE_STRUCT' ) bld.SAMBA3_SUBSYSTEM('NDR_SMBXSRV', diff --git a/source3/locking/locking.c b/source3/locking/locking.c index a320068e6dc9..9194dd388e65 100644 --- a/source3/locking/locking.c +++ b/source3/locking/locking.c @@ -608,6 +608,7 @@ bool is_valid_share_mode_entry(const struct share_mode_entry *e) num_props += ((e->op_type == NO_OPLOCK) ? 1 : 0); num_props += (EXCLUSIVE_OPLOCK_TYPE(e->op_type) ? 1 : 0); num_props += (LEVEL_II_OPLOCK_TYPE(e->op_type) ? 1 : 0); + num_props += (e->op_type == LEASE_OPLOCK); if ((num_props > 1) && serverid_exists(&e->pid)) { smb_panic("Invalid share mode entry"); @@ -693,11 +694,21 @@ void remove_stale_share_mode_entries(struct share_mode_data *d) } } -bool set_share_mode(struct share_mode_lock *lck, files_struct *fsp, - uid_t uid, uint64_t mid, uint16 op_type) +bool set_share_mode(struct share_mode_lock *lck, struct files_struct *fsp, + uid_t uid, uint64_t mid, uint16_t op_type, + uint32_t lease_idx) { struct share_mode_data *d = lck->data; struct share_mode_entry *tmp, *e; + struct share_mode_lease *lease = NULL; + + if (lease_idx == UINT32_MAX) { + lease = NULL; + } else if (lease_idx >= d->num_leases) { + return false; + } else { + lease = &d->leases[lease_idx]; + } tmp = talloc_realloc(d, d->share_modes, struct share_mode_entry, d->num_share_modes+1); @@ -716,6 +727,8 @@ bool set_share_mode(struct share_mode_lock *lck, files_struct *fsp, e->access_mask = fsp->access_mask; e->op_mid = mid; e->op_type = op_type; + e->lease_idx = lease_idx; + e->lease = lease; e->time.tv_sec = fsp->open_time.tv_sec; e->time.tv_usec = fsp->open_time.tv_usec; e->id = fsp->file_id; diff --git a/source3/locking/proto.h b/source3/locking/proto.h index 8eccff8370bc..6b60330fd88e 100644 --- a/source3/locking/proto.h +++ b/source3/locking/proto.h @@ -166,8 +166,9 @@ void get_file_infos(struct file_id id, struct timespec *write_time); bool is_valid_share_mode_entry(const struct share_mode_entry *e); bool share_mode_stale_pid(struct share_mode_data *d, uint32_t idx); -bool set_share_mode(struct share_mode_lock *lck, files_struct *fsp, - uid_t uid, uint64_t mid, uint16 op_type); +bool set_share_mode(struct share_mode_lock *lck, struct files_struct *fsp, + uid_t uid, uint64_t mid, uint16_t op_type, + uint32_t lease_idx); void remove_stale_share_mode_entries(struct share_mode_data *d); bool del_share_mode(struct share_mode_lock *lck, files_struct *fsp); bool mark_share_mode_disconnected(struct share_mode_lock *lck, diff --git a/source3/locking/share_mode_lock.c b/source3/locking/share_mode_lock.c index 6447c617406b..2ae7c3373b39 100644 --- a/source3/locking/share_mode_lock.c +++ b/source3/locking/share_mode_lock.c @@ -154,7 +154,17 @@ static struct share_mode_data *parse_share_modes(TALLOC_CTX *mem_ctx, */ for (i=0; inum_share_modes; i++) { - d->share_modes[i].stale = false; + struct share_mode_entry *e = &d->share_modes[i]; + + e->stale = false; + e->lease = NULL; + if (e->op_type != LEASE_OPLOCK) { + continue; + } + if (e->lease_idx >= d->num_leases) { + continue; + } + e->lease = &d->leases[e->lease_idx]; } d->modified = false; d->fresh = false; diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 1952823d37fb..c14d2ebf59bf 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -1568,7 +1568,8 @@ static NTSTATUS grant_fsp_oplock_type(struct smb_request *req, ok = set_share_mode(lck, fsp, get_current_uid(fsp->conn), req ? req->mid : 0, - fsp->oplock_type); + fsp->oplock_type, + UINT32_MAX); if (!ok) { return NT_STATUS_NO_MEMORY; } @@ -3080,6 +3081,7 @@ static NTSTATUS open_directory(connection_struct *conn, NTSTATUS status; struct timespec mtimespec; int info = 0; + bool ok; if (is_ntfs_stream_smb_fname(smb_dname)) { DEBUG(2, ("open_directory: %s is a stream name!\n", @@ -3336,8 +3338,10 @@ static NTSTATUS open_directory(connection_struct *conn, return status; } - if (!set_share_mode(lck, fsp, get_current_uid(conn), - req ? req->mid : 0, NO_OPLOCK)) { + ok = set_share_mode(lck, fsp, get_current_uid(conn), + req ? req->mid : 0, NO_OPLOCK, + UINT32_MAX); + if (!ok) { TALLOC_FREE(lck); fd_close(fsp); file_free(req, fsp); diff --git a/source3/utils/status.c b/source3/utils/status.c index 4e1dae78e822..cd6a988b2faa 100644 --- a/source3/utils/status.c +++ b/source3/utils/status.c @@ -175,6 +175,15 @@ static int print_share_mode(const struct share_mode_entry *e, d_printf("BATCH "); } else if (e->op_type & LEVEL_II_OPLOCK) { d_printf("LEVEL_II "); + } else if (e->op_type == LEASE_OPLOCK) { + uint32_t lstate = e->lease->current_state; + d_printf("LEASE(%s%s%s)%s%s%s ", + (lstate & SMB2_LEASE_READ)?"R":"", + (lstate & SMB2_LEASE_WRITE)?"W":"", + (lstate & SMB2_LEASE_HANDLE)?"H":"", + (lstate & SMB2_LEASE_READ)?"":" ", + (lstate & SMB2_LEASE_WRITE)?"":" ", + (lstate & SMB2_LEASE_HANDLE)?"":" "); } else { d_printf("NONE "); } -- 2.34.1