The branch, master has been updated via bfbe24d8274 leases_db: Make leases_db_del use leases_db_do_locked via 885d433b468 leases_db: Make leases_db_add use leases_db_do_locked via ee53763a3e7 leases_db: Make leases_db_rename atomic via cc4513dd4d3 smbd: Factor out map_lease_type_to_oplock via bcb27521259 lib: Initialize variables in parse_resolvconf_fp via c0b2272a7d1 lib: Initialize getline() arguments from b1582a4d09f CVE-2019-3880 s3: rpc: winreg: Remove implementations of SaveKey/RestoreKey.
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit bfbe24d827425683c094a479e0f0158c5580bda7 Author: Volker Lendecke <v...@samba.org> Date: Mon Apr 8 15:38:01 2019 +0200 leases_db: Make leases_db_del use leases_db_do_locked Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> Autobuild-User(master): Jeremy Allison <j...@samba.org> Autobuild-Date(master): Tue Apr 9 19:31:09 UTC 2019 on sn-devel-144 commit 885d433b468216a86b2963c6b4af896b254caa65 Author: Volker Lendecke <v...@samba.org> Date: Mon Apr 8 15:33:30 2019 +0200 leases_db: Make leases_db_add use leases_db_do_locked Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit ee53763a3e7ce13f534dd4071a0ce60a29671e67 Author: Volker Lendecke <v...@samba.org> Date: Mon Apr 8 15:18:31 2019 +0200 leases_db: Make leases_db_rename atomic Do the rename under one lock to protect against potential races while we don't hold it. Factor out the NDR marshalling into leases_db_do_locked(), leaving the rename function pretty simple. Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit cc4513dd4d35f2d9ff4649f595bd85b0bb3a2fa3 Author: Volker Lendecke <v...@samba.org> Date: Tue Sep 18 10:53:23 2018 +0200 smbd: Factor out map_lease_type_to_oplock grant_fsp_oplock_type has enough complex logic, make this a bit shorter Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Jeremy Allison <j...@samba.org> commit bcb2752125986cbbf33a9388bd6420bb2af48ef6 Author: Volker Lendecke <v...@samba.org> Date: Tue Apr 9 12:49:00 2019 +0200 lib: Initialize variables in parse_resolvconf_fp Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> commit c0b2272a7d15d266ce64c86cf6a313b5b0fb67fd Author: Volker Lendecke <v...@samba.org> Date: Tue Apr 9 12:47:13 2019 +0200 lib: Initialize getline() arguments Keep "len" valid across the loop iterations for getline to consume Bug: https://bugzilla.samba.org/show_bug.cgi?id=13892 Signed-off-by: Volker Lendecke <v...@samba.org> Reviewed-by: Stefan Metzmacher <me...@samba.org> ----------------------------------------------------------------------- Summary of changes: libcli/dns/resolvconf.c | 8 +- source3/locking/leases_db.c | 372 ++++++++++++++++++++++++-------------------- source3/smbd/open.c | 36 +++-- 3 files changed, 230 insertions(+), 186 deletions(-) Changeset truncated at 500 lines: diff --git a/libcli/dns/resolvconf.c b/libcli/dns/resolvconf.c index 90d4e6a74b6..5cf8b4e7882 100644 --- a/libcli/dns/resolvconf.c +++ b/libcli/dns/resolvconf.c @@ -30,15 +30,15 @@ int parse_resolvconf_fp( size_t *pnum_nameservers) { char *line = NULL; + size_t len = 0; char **nameservers = NULL; size_t num_nameservers = 0; int ret = 0; while (true) { - char *saveptr, *option, *ns; - char **tmp; - ssize_t n; - size_t len; + char *saveptr = NULL, *option = NULL, *ns = NULL; + char **tmp = NULL; + ssize_t n = 0; n = getline(&line, &len, fp); if (n < 0) { diff --git a/source3/locking/leases_db.c b/source3/locking/leases_db.c index 31576280fb6..3893841b172 100644 --- a/source3/locking/leases_db.c +++ b/source3/locking/leases_db.c @@ -86,223 +86,226 @@ static TDB_DATA leases_db_key(struct leases_db_key_buf *buf, return (TDB_DATA) { .dptr = buf->buf, .dsize = sizeof(buf->buf) }; } -NTSTATUS leases_db_add(const struct GUID *client_guid, - const struct smb2_lease_key *lease_key, - const struct file_id *id, - const char *servicepath, - const char *base_name, - const char *stream_name) -{ - struct leases_db_key_buf keybuf; - TDB_DATA db_key = leases_db_key(&keybuf, client_guid, lease_key); - TDB_DATA db_value; - DATA_BLOB blob; - struct db_record *rec; +struct leases_db_do_locked_state { + void (*fn)(struct leases_db_value *value, + bool *modified, + void *private_data); + void *private_data; NTSTATUS status; - struct leases_db_value new_value; - struct leases_db_file new_file; +}; + +static void leases_db_do_locked_fn(struct db_record *rec, void *private_data) +{ + struct leases_db_do_locked_state *state = private_data; + TDB_DATA db_value = dbwrap_record_get_value(rec); + DATA_BLOB blob = { .data = db_value.dptr, .length = db_value.dsize }; struct leases_db_value *value = NULL; enum ndr_err_code ndr_err; + bool modified = false; - if (!leases_db_init(false)) { - return NT_STATUS_INTERNAL_ERROR; - } - - rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key); - if (rec == NULL) { - return NT_STATUS_INTERNAL_ERROR; + value = talloc_zero(talloc_tos(), struct leases_db_value); + if (value == NULL) { + state->status = NT_STATUS_NO_MEMORY; + goto done; } - db_value = dbwrap_record_get_value(rec); - if (db_value.dsize != 0) { - uint32_t i; - - DEBUG(10, ("%s: record exists\n", __func__)); - - value = talloc(talloc_tos(), struct leases_db_value); - if (value == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; - } - - blob.data = db_value.dptr; - blob.length = db_value.dsize; - + if (blob.length != 0) { ndr_err = ndr_pull_struct_blob_all( - &blob, value, value, + &blob, + value, + value, (ndr_pull_flags_fn_t)ndr_pull_leases_db_value); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n", - __func__, ndr_errstr(ndr_err))); - status = ndr_map_error2ntstatus(ndr_err); - goto out; + DBG_DEBUG("ndr_pull_struct_blob_failed: %s\n", + ndr_errstr(ndr_err)); + state->status = ndr_map_error2ntstatus(ndr_err); + goto done; } + } - /* id must be unique. */ - for (i = 0; i < value->num_files; i++) { - if (file_id_equal(id, &value->files[i].id)) { - status = NT_STATUS_OBJECT_NAME_COLLISION; - goto out; - } - } + state->fn(value, &modified, state->private_data); + + if (!modified) { + goto done; + } - value->files = talloc_realloc(value, value->files, - struct leases_db_file, - value->num_files + 1); - if (value->files == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + if (value->num_files == 0) { + state->status = dbwrap_record_delete(rec); + if (!NT_STATUS_IS_OK(state->status)) { + DBG_DEBUG("dbwrap_record_delete returned %s\n", + nt_errstr(state->status)); } - value->files[value->num_files].id = *id; - value->files[value->num_files].servicepath = servicepath; - value->files[value->num_files].base_name = base_name; - value->files[value->num_files].stream_name = stream_name; - value->num_files += 1; - - } else { - DEBUG(10, ("%s: new record\n", __func__)); - - new_file = (struct leases_db_file) { - .id = *id, - .servicepath = servicepath, - .base_name = base_name, - .stream_name = stream_name, - }; - - new_value = (struct leases_db_value) { - .num_files = 1, - .files = &new_file, - }; - value = &new_value; + goto done; } ndr_err = ndr_push_struct_blob( - &blob, talloc_tos(), value, + &blob, + value, + value, (ndr_push_flags_fn_t)ndr_push_leases_db_value); if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n", - __func__, ndr_errstr(ndr_err))); - status = ndr_map_error2ntstatus(ndr_err); - goto out; + DBG_DEBUG("ndr_push_struct_blob_failed: %s\n", + ndr_errstr(ndr_err)); + state->status = ndr_map_error2ntstatus(ndr_err); + goto done; } if (DEBUGLEVEL >= 10) { - DEBUG(10, ("%s:\n", __func__)); + DBG_DEBUG("\n"); NDR_PRINT_DEBUG(leases_db_value, value); } db_value = make_tdb_data(blob.data, blob.length); - status = dbwrap_record_store(rec, db_value, 0); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("%s: dbwrap_record_store returned %s\n", - __func__, nt_errstr(status))); + state->status = dbwrap_record_store(rec, db_value, 0); + if (!NT_STATUS_IS_OK(state->status)) { + DBG_DEBUG("dbwrap_record_store returned %s\n", + nt_errstr(state->status)); } - out: - - if (value != &new_value) { - TALLOC_FREE(value); - } - TALLOC_FREE(rec); - return status; +done: + TALLOC_FREE(value); } -NTSTATUS leases_db_del(const struct GUID *client_guid, - const struct smb2_lease_key *lease_key, - const struct file_id *id) +static NTSTATUS leases_db_do_locked( + const struct GUID *client_guid, + const struct smb2_lease_key *lease_key, + void (*fn)(struct leases_db_value *value, + bool *modified, + void *private_data), + void *private_data) { struct leases_db_key_buf keybuf; TDB_DATA db_key = leases_db_key(&keybuf, client_guid, lease_key); - TDB_DATA db_value; - struct db_record *rec; + struct leases_db_do_locked_state state = { + .fn = fn, .private_data = private_data, + }; NTSTATUS status; - struct leases_db_value *value; - enum ndr_err_code ndr_err; - DATA_BLOB blob; - uint32_t i; if (!leases_db_init(false)) { return NT_STATUS_INTERNAL_ERROR; } - rec = dbwrap_fetch_locked(leases_db, talloc_tos(), db_key); - if (rec == NULL) { - return NT_STATUS_NOT_FOUND; + status = dbwrap_do_locked( + leases_db, db_key, leases_db_do_locked_fn, &state); + if (!NT_STATUS_IS_OK(status)) { + return status; } - db_value = dbwrap_record_get_value(rec); - if (db_value.dsize == 0) { - status = NT_STATUS_INTERNAL_ERROR; - goto out; + return state.status; +} + +struct leases_db_add_state { + const struct file_id *id; + const char *servicepath; + const char *base_name; + const char *stream_name; + NTSTATUS status; +}; + +static void leases_db_add_fn( + struct leases_db_value *value, bool *modified, void *private_data) +{ + struct leases_db_add_state *state = private_data; + struct leases_db_file *tmp = NULL; + uint32_t i; + + /* id must be unique. */ + for (i = 0; i < value->num_files; i++) { + if (file_id_equal(state->id, &value->files[i].id)) { + state->status = NT_STATUS_OBJECT_NAME_COLLISION; + return; + } } - value = talloc(rec, struct leases_db_value); - if (value == NULL) { - status = NT_STATUS_NO_MEMORY; - goto out; + tmp = talloc_realloc( + value, + value->files, + struct leases_db_file, + value->num_files + 1); + if (tmp == NULL) { + state->status = NT_STATUS_NO_MEMORY; + return; } + value->files = tmp; - blob.data = db_value.dptr; - blob.length = db_value.dsize; + value->files[value->num_files] = (struct leases_db_file) { + .id = *state->id, + .servicepath = state->servicepath, + .base_name = state->base_name, + .stream_name = state->stream_name, + }; + value->num_files += 1; - ndr_err = ndr_pull_struct_blob_all( - &blob, value, value, - (ndr_pull_flags_fn_t)ndr_pull_leases_db_value); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("%s: ndr_pull_struct_blob_failed: %s\n", - __func__, ndr_errstr(ndr_err))); - status = ndr_map_error2ntstatus(ndr_err); - goto out; + *modified = true; +} + +NTSTATUS leases_db_add(const struct GUID *client_guid, + const struct smb2_lease_key *lease_key, + const struct file_id *id, + const char *servicepath, + const char *base_name, + const char *stream_name) +{ + struct leases_db_add_state state = { + .id = id, + .servicepath = servicepath, + .base_name = base_name, + .stream_name = stream_name, + }; + NTSTATUS status; + + status = leases_db_do_locked( + client_guid, lease_key, leases_db_add_fn, &state); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("leases_db_do_locked failed: %s\n", + nt_errstr(status)); + return status; } + return state.status; +} + +struct leases_db_del_state { + const struct file_id *id; + NTSTATUS status; +}; + +static void leases_db_del_fn( + struct leases_db_value *value, bool *modified, void *private_data) +{ + struct leases_db_del_state *state = private_data; + uint32_t i; - /* id must exist. */ for (i = 0; i < value->num_files; i++) { - if (file_id_equal(id, &value->files[i].id)) { + if (file_id_equal(state->id, &value->files[i].id)) { break; } } - if (i == value->num_files) { - status = NT_STATUS_NOT_FOUND; - goto out; + state->status = NT_STATUS_NOT_FOUND; + return; } value->files[i] = value->files[value->num_files-1]; value->num_files -= 1; - if (value->num_files == 0) { - DEBUG(10, ("%s: deleting record\n", __func__)); - status = dbwrap_record_delete(rec); - } else { - DEBUG(10, ("%s: updating record\n", __func__)); - ndr_err = ndr_push_struct_blob( - &blob, rec, value, - (ndr_push_flags_fn_t)ndr_push_leases_db_value); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(10, ("%s: ndr_push_struct_blob_failed: %s\n", - __func__, ndr_errstr(ndr_err))); - status = ndr_map_error2ntstatus(ndr_err); - goto out; - } - - if (DEBUGLEVEL >= 10) { - DEBUG(10, ("%s:\n", __func__)); - NDR_PRINT_DEBUG(leases_db_value, value); - } + *modified = true; +} - db_value = make_tdb_data(blob.data, blob.length); +NTSTATUS leases_db_del(const struct GUID *client_guid, + const struct smb2_lease_key *lease_key, + const struct file_id *id) +{ + struct leases_db_del_state state = { .id = id }; + NTSTATUS status; - status = dbwrap_record_store(rec, db_value, 0); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(10, ("%s: dbwrap_record_store returned %s\n", - __func__, nt_errstr(status))); - } + status = leases_db_do_locked( + client_guid, lease_key, leases_db_del_fn, &state); + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("leases_db_do_locked failed: %s\n", + nt_errstr(status)); + return status; } - - out: - - TALLOC_FREE(rec); - return status; + return state.status; } struct leases_db_fetch_state { @@ -381,6 +384,40 @@ NTSTATUS leases_db_parse(const struct GUID *client_guid, return state.status; } +struct leases_db_rename_state { + const struct file_id *id; + const char *servicename_new; + const char *filename_new; + const char *stream_name_new; + NTSTATUS status; +}; + +static void leases_db_rename_fn( + struct leases_db_value *value, bool *modified, void *private_data) +{ + struct leases_db_rename_state *state = private_data; + struct leases_db_file *file = NULL; + uint32_t i; + + /* id must exist. */ + for (i = 0; i < value->num_files; i++) { + if (file_id_equal(state->id, &value->files[i].id)) { + break; + } + } + if (i == value->num_files) { + state->status = NT_STATUS_NOT_FOUND; + return; + } + + file = &value->files[i]; + file->servicepath = state->servicename_new; + file->base_name = state->filename_new; + file->stream_name = state->stream_name_new; + + *modified = true; +} + NTSTATUS leases_db_rename(const struct GUID *client_guid, const struct smb2_lease_key *lease_key, const struct file_id *id, @@ -388,21 +425,22 @@ NTSTATUS leases_db_rename(const struct GUID *client_guid, const char *filename_new, const char *stream_name_new) { + struct leases_db_rename_state state = { + .id = id, + .servicename_new = servicename_new, + .filename_new = filename_new, + .stream_name_new = stream_name_new, + }; NTSTATUS status; - status = leases_db_del(client_guid, - lease_key, - id); + status = leases_db_do_locked( + client_guid, lease_key, leases_db_rename_fn, &state); if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("leases_db_do_locked failed: %s\n", + nt_errstr(status)); return status; } - - return leases_db_add(client_guid, - lease_key, - id, - servicename_new, - filename_new, - stream_name_new); + return state.status; } NTSTATUS leases_db_copy_file_ids(TALLOC_CTX *mem_ctx, diff --git a/source3/smbd/open.c b/source3/smbd/open.c index 22f6715c6c0..167d82f0b13 100644 --- a/source3/smbd/open.c +++ b/source3/smbd/open.c @@ -2166,6 +2166,26 @@ static bool is_same_lease(const files_struct *fsp, &d->leases[e->lease_idx].lease_key); } +static int map_lease_type_to_oplock(uint32_t lease_type) +{ + int result = NO_OPLOCK; + + switch (lease_type) { + case SMB2_LEASE_READ|SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE: -- Samba Shared Repository