The branch, master has been updated via 9f4eda9 selftest: Fix copyright header on samba.dsdb_lock via de3f0d8 ctdb-recovery-helper: Deregister message handler in error paths via cb5e6e8 ctdb-client: Add async version for ctdb_client_init() via 43145c8 ctdb-common: Avoid using void ** argument via 495cc4e ctdb-build: Apply dependency to correct subsystem from 2a8b507 selftest: Add cleanup of ForeignSecurityPrincipal in samba.dsdb test
https://git.samba.org/?p=samba.git;a=shortlog;h=master - Log ----------------------------------------------------------------- commit 9f4eda9c24ff4c051002080e862757b69c09b175 Author: Andrew Bartlett <abart...@samba.org> Date: Wed Dec 6 14:31:54 2017 +1300 selftest: Fix copyright header on samba.dsdb_lock BUG: https://bugzilla.samba.org/show_bug.cgi?id=13178 Signed-off-by: Andrew Bartlett <abart...@samba.org> Reviewed-by: Martin Schwenke <mar...@meltin.net> Autobuild-User(master): Martin Schwenke <mart...@samba.org> Autobuild-Date(master): Wed Dec 13 13:03:16 CET 2017 on sn-devel-144 commit de3f0d889b3667eb165ab1004fdfff3a05046110 Author: Amitay Isaacs <ami...@gmail.com> Date: Wed Dec 13 16:12:09 2017 +1100 ctdb-recovery-helper: Deregister message handler in error paths BUG: https://bugzilla.samba.org/show_bug.cgi?id=13188 If PULL_DB control times out but the remote node is still sending the data, then the tevent_req for pull_database_send will be freed without removing the message handler. So when the data is received, srvid handler will be called and it will try to access tevent_req which will result in use-after-free and abort. Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit cb5e6e8c798b19610dfaa505fdfc5b2cab3fa19b Author: Amitay Isaacs <ami...@gmail.com> Date: Tue Nov 28 21:17:37 2017 +1100 ctdb-client: Add async version for ctdb_client_init() Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit 43145c88fe75d57ff66ea95d9db0ce503a2e8c03 Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Nov 9 16:37:15 2017 +1100 ctdb-common: Avoid using void ** argument Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> commit 495cc4ed2255b334fa6fa75424add7c43575ab74 Author: Amitay Isaacs <ami...@gmail.com> Date: Thu Nov 2 17:33:19 2017 +1100 ctdb-build: Apply dependency to correct subsystem Signed-off-by: Amitay Isaacs <ami...@gmail.com> Reviewed-by: Martin Schwenke <mar...@meltin.net> ----------------------------------------------------------------------- Summary of changes: ctdb/client/client.h | 27 ++++- ctdb/client/client_connect.c | 205 +++++++++++++++++++++++++------------ ctdb/common/sock_client.c | 4 +- ctdb/common/sock_client.h | 2 +- ctdb/server/ctdb_recovery_helper.c | 16 ++- ctdb/wscript | 4 +- python/samba/tests/dsdb_lock.py | 4 +- 7 files changed, 185 insertions(+), 77 deletions(-) Changeset truncated at 500 lines: diff --git a/ctdb/client/client.h b/ctdb/client/client.h index 5be54b2..e792047 100644 --- a/ctdb/client/client.h +++ b/ctdb/client/client.h @@ -83,7 +83,7 @@ typedef void (*ctdb_tunnel_callback_func_t)(struct ctdb_tunnel_context *tctx, void *private_data); /** - * @brief Initialize and connect to ctdb daemon + * @brief Async computation start to initialize a connection to ctdb daemon * * This returns a ctdb client context. Freeing this context will free the * connection to ctdb daemon and any memory associated with it. @@ -102,6 +102,31 @@ typedef void (*ctdb_tunnel_callback_func_t)(struct ctdb_tunnel_context *tctx, * @param[in] mem_ctx Talloc memory context * @param[in] ev Tevent context * @param[in] sockpath Path to ctdb daemon unix domain socket + * @return new tevent request, NULL on failure + */ +struct tevent_req *ctdb_client_init_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *sockpath); + +/** + * @brief Async computation end to initialize a connection to ctdb daemon + * + * @param[in] req Tevent request + * @param[out] perr errno in case of failure + * @param[in] mem_ctx Talloc memory context + * @param[out] result The new ctdb client context + * @return true on success, false on failure + */ +bool ctdb_client_init_recv(struct tevent_req *req, int *perr, + TALLOC_CTX *mem_ctx, + struct ctdb_client_context **result); + +/** + * @brief Sync wrapper to initialize ctdb connection + * + * @param[in] mem_ctx Talloc memory context + * @param[in] ev Tevent context + * @param[in] sockpath Path to ctdb daemon unix domain socket * @param[out] result The new ctdb client context * @return 0 on succcess, errno on failure */ diff --git a/ctdb/client/client_connect.c b/ctdb/client/client_connect.c index ed4371f..89a602d 100644 --- a/ctdb/client/client_connect.c +++ b/ctdb/client/client_connect.c @@ -40,58 +40,127 @@ #include "client/client.h" #include "client/client_sync.h" -static int ctdb_client_connect(struct ctdb_client_context *client, - struct tevent_context *ev, - const char *sockpath); +static void client_read_handler(uint8_t *buf, size_t buflen, + void *private_data); +static void client_dead_handler(void *private_data); + +struct ctdb_client_init_state { + struct ctdb_client_context *client; +}; static int ctdb_client_context_destructor(struct ctdb_client_context *client); +static void ctdb_client_init_done(struct tevent_req *subreq); -int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, - const char *sockpath, struct ctdb_client_context **out) +struct tevent_req *ctdb_client_init_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + const char *sockpath) { + struct tevent_req *req, *subreq; + struct ctdb_client_init_state *state; struct ctdb_client_context *client; + struct ctdb_req_control request; + struct sockaddr_un addr; + size_t len; int ret; - client = talloc_zero(mem_ctx, struct ctdb_client_context); - if (client == NULL) { - DEBUG(DEBUG_ERR, (__location__ " memory allocation error\n")); - return ENOMEM; + req = tevent_req_create(mem_ctx, &state, + struct ctdb_client_init_state); + if (req == NULL) { + return NULL; + } + + if (sockpath == NULL) { + D_ERR("socket path cannot be NULL\n"); + tevent_req_error(req, EINVAL); + return tevent_req_post(req, ev); + } + + client = talloc_zero(state, struct ctdb_client_context); + if (tevent_req_nomem(client, req)) { + return tevent_req_post(req, ev); } ret = reqid_init(client, INT_MAX-200, &client->idr); if (ret != 0) { - DEBUG(DEBUG_ERR, ("reqid_init() failed, ret=%d\n", ret)); + D_ERR("reqid_init() failed, ret=%d\n", ret); talloc_free(client); - return ret; + tevent_req_error(req, ret); + return tevent_req_post(req, ev); } ret = srvid_init(client, &client->srv); if (ret != 0) { DEBUG(DEBUG_ERR, ("srvid_init() failed, ret=%d\n", ret)); talloc_free(client); - return ret; + tevent_req_error(req, ret); + return tevent_req_post(req, ev); } ret = srvid_init(client, &client->tunnels); if (ret != 0) { DEBUG(DEBUG_ERR, ("srvid_init() failed, ret=%d\n", ret)); talloc_free(client); - return ret; + tevent_req_error(req, ret); + return tevent_req_post(req, ev); } - client->fd = -1; - client->pnn = CTDB_UNKNOWN_PNN; + memset(&addr, 0, sizeof(addr)); + addr.sun_family = AF_UNIX; + len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); + if (len != strlen(sockpath)) { + D_ERR("socket path too long, len=%zu\n", strlen(sockpath)); + talloc_free(client); + tevent_req_error(req, ENAMETOOLONG); + return tevent_req_post(req, ev); + } - ret = ctdb_client_connect(client, ev, sockpath); + client->fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (client->fd == -1) { + ret = errno; + D_ERR("socket() failed, errno=%d\n", ret); + talloc_free(client); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + ret = connect(client->fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret == -1) { + ret = errno; + DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret)); + close(client->fd); + talloc_free(client); + tevent_req_error(req, ret); + return tevent_req_post(req, ev); + } + + ret = comm_setup(client, ev, client->fd, client_read_handler, client, + client_dead_handler, client, &client->comm); if (ret != 0) { + DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret)); + close(client->fd); talloc_free(client); - return ret; + tevent_req_error(req, ret); + return tevent_req_post(req, ev); } + client->pnn = CTDB_UNKNOWN_PNN; + talloc_set_destructor(client, ctdb_client_context_destructor); - *out = client; - return 0; + state->client = client; + + ctdb_req_control_get_pnn(&request); + subreq = ctdb_client_control_send(state, ev, client, + CTDB_CURRENT_NODE, + tevent_timeval_zero(), + &request); + if (tevent_req_nomem(subreq, req)) { + TALLOC_FREE(state->client); + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, ctdb_client_init_done, req); + + return req; } static int ctdb_client_context_destructor(struct ctdb_client_context *client) @@ -103,63 +172,69 @@ static int ctdb_client_context_destructor(struct ctdb_client_context *client) return 0; } -static void client_read_handler(uint8_t *buf, size_t buflen, - void *private_data); -static void client_dead_handler(void *private_data); - -static int ctdb_client_connect(struct ctdb_client_context *client, - struct tevent_context *ev, const char *sockpath) +static void ctdb_client_init_done(struct tevent_req *subreq) { - struct sockaddr_un addr; - size_t len; - int fd, ret; + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct ctdb_client_init_state *state = tevent_req_data( + req, struct ctdb_client_init_state); + struct ctdb_reply_control *reply; + int ret; + bool status; - if (sockpath == NULL) { - DEBUG(DEBUG_ERR, ("socket path cannot be NULL\n")); - return EINVAL; + status = ctdb_client_control_recv(subreq, &ret, state, &reply); + TALLOC_FREE(subreq); + if (! status) { + tevent_req_error(req, ret); + return; } - memset(&addr, 0, sizeof(addr)); - addr.sun_family = AF_UNIX; - len = strlcpy(addr.sun_path, sockpath, sizeof(addr.sun_path)); - if (len != strlen(sockpath)) { - DEBUG(DEBUG_ERR, ("socket path too long, len=%zu\n", - strlen(sockpath))); - return ENAMETOOLONG; + ret = ctdb_reply_control_get_pnn(reply, &state->client->pnn); + if (ret != 0) { + tevent_req_error(req, ret); + return; } - fd = socket(AF_UNIX, SOCK_STREAM, 0); - if (fd == -1) { - ret = errno; - DEBUG(DEBUG_ERR, ("socket() failed, errno=%d\n", ret)); - return ret; - } + tevent_req_done(req); +} - ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); - if (ret == -1) { - ret = errno; - DEBUG(DEBUG_ERR, ("connect() failed, errno=%d\n", ret)); - close(fd); - return ret; +bool ctdb_client_init_recv(struct tevent_req *req, int *perr, + TALLOC_CTX *mem_ctx, + struct ctdb_client_context **result) +{ + struct ctdb_client_init_state *state = tevent_req_data( + req, struct ctdb_client_init_state); + int ret; + + if (tevent_req_is_unix_error(req, &ret)) { + if (perr != NULL) { + *perr = ret; + } + return false; } - client->fd = fd; - ret = comm_setup(client, ev, fd, client_read_handler, client, - client_dead_handler, client, &client->comm); - if (ret != 0) { - DEBUG(DEBUG_ERR, ("comm_setup() failed, ret=%d\n", ret)); - close(fd); - client->fd = -1; - return ret; + *result = talloc_steal(mem_ctx, state->client); + return true; +} + + +int ctdb_client_init(TALLOC_CTX *mem_ctx, struct tevent_context *ev, + const char *sockpath, struct ctdb_client_context **out) +{ + struct tevent_req *req; + int ret; + bool status; + + req = ctdb_client_init_send(mem_ctx, ev, sockpath); + if (req == NULL) { + return ENOMEM; } - ret = ctdb_ctrl_get_pnn(client, ev, client, CTDB_CURRENT_NODE, - tevent_timeval_zero(), &client->pnn); - if (ret != 0) { - DEBUG(DEBUG_ERR, ("failed to get current node pnn\n")); - close(fd); - client->fd = -1; - TALLOC_FREE(client->comm); + tevent_req_poll(req, ev); + + status = ctdb_client_init_recv(req, &ret, mem_ctx, out); + TALLOC_FREE(req); + if (! status) { return ret; } diff --git a/ctdb/common/sock_client.c b/ctdb/common/sock_client.c index e5f993e..ced7050 100644 --- a/ctdb/common/sock_client.c +++ b/ctdb/common/sock_client.c @@ -311,7 +311,7 @@ static void sock_client_msg_reply(struct sock_client_context *sockc, } bool sock_client_msg_recv(struct tevent_req *req, int *perr, - TALLOC_CTX *mem_ctx, void **reply) + TALLOC_CTX *mem_ctx, void *reply) { struct sock_client_msg_state *state = tevent_req_data( req, struct sock_client_msg_state); @@ -325,7 +325,7 @@ bool sock_client_msg_recv(struct tevent_req *req, int *perr, } if (reply != NULL) { - *reply = talloc_steal(mem_ctx, state->reply); + *(void **)reply = talloc_steal(mem_ctx, state->reply); } return true; diff --git a/ctdb/common/sock_client.h b/ctdb/common/sock_client.h index c640767..c5822a0 100644 --- a/ctdb/common/sock_client.h +++ b/ctdb/common/sock_client.h @@ -124,6 +124,6 @@ struct tevent_req *sock_client_msg_send(TALLOC_CTX *mem_ctx, * @return true on success, false on failure */ bool sock_client_msg_recv(struct tevent_req *req, int *perr, - TALLOC_CTX *mem_ctx, void **reply); + TALLOC_CTX *mem_ctx, void *reply); #endif /* __CTDB_SOCK_CLIENT_H__ */ diff --git a/ctdb/server/ctdb_recovery_helper.c b/ctdb/server/ctdb_recovery_helper.c index ab9ab41..2a10b07 100644 --- a/ctdb/server/ctdb_recovery_helper.c +++ b/ctdb/server/ctdb_recovery_helper.c @@ -397,6 +397,7 @@ struct pull_database_state { uint32_t pnn; uint64_t srvid; int num_records; + int result; }; static void pull_database_handler(uint64_t srvid, TDB_DATA data, @@ -595,8 +596,8 @@ static void pull_database_new_done(struct tevent_req *subreq) if (! status) { D_ERR("control DB_PULL failed for %s on node %u, ret=%d\n", recdb_name(state->recdb), state->pnn, ret); - tevent_req_error(req, ret); - return; + state->result = ret; + goto unregister; } ret = ctdb_reply_control_db_pull(reply, &num_records); @@ -605,13 +606,15 @@ static void pull_database_new_done(struct tevent_req *subreq) D_ERR("mismatch (%u != %u) in DB_PULL records for db %s\n", num_records, state->num_records, recdb_name(state->recdb)); - tevent_req_error(req, EIO); - return; + state->result = EIO; + goto unregister; } D_INFO("Pulled %d records for db %s from node %d\n", state->num_records, recdb_name(state->recdb), state->pnn); +unregister: + subreq = ctdb_client_remove_message_handler_send( state, state->ev, state->client, state->srvid, req); @@ -639,6 +642,11 @@ static void pull_database_unregister_done(struct tevent_req *subreq) return; } + if (state->result != 0) { + tevent_req_error(req, state->result); + return; + } + tevent_req_done(req); } diff --git a/ctdb/wscript b/ctdb/wscript index f5a2481..8774b99 100644 --- a/ctdb/wscript +++ b/ctdb/wscript @@ -442,7 +442,7 @@ def build(bld): source=bld.SUBDIR('common', '''sock_daemon.c'''), deps='''samba-util ctdb-util tevent-util - replace talloc tevent''') + LIBASYNC_REQ replace talloc tevent''') bld.SAMBA_SUBSYSTEM('ctdb-ipalloc', source=bld.SUBDIR('server', @@ -511,7 +511,7 @@ def build(bld): bld.SAMBA_BINARY('ctdb_eventd', source='server/ctdb_eventd.c', deps='''ctdb-server-util ctdb-protocol ctdb-protocol-util - ctdb-util samba-util LIBASYNC_REQ replace popt''', + ctdb-util samba-util replace popt''', install_path='${CTDB_HELPER_BINDIR}') bld.SAMBA_BINARY('ctdb_lock_helper', diff --git a/python/samba/tests/dsdb_lock.py b/python/samba/tests/dsdb_lock.py index 9cc93aa..cd3851e 100644 --- a/python/samba/tests/dsdb_lock.py +++ b/python/samba/tests/dsdb_lock.py @@ -1,5 +1,5 @@ -# Unix SMB/CIFS implementation. Tests for SamDB -# Copyright (C) Jelmer Vernooij <jel...@samba.org> 2008 +# Unix SMB/CIFS implementation. Tests for DSDB locking +# Copyright (C) Andrew Bartlett <abart...@samba.org> 2017 # # 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 -- Samba Shared Repository