diff --git a/src/monitor/monitor.c b/src/monitor/monitor.c index 6366c0dee12..1f9cd63520e 100644 --- a/src/monitor/monitor.c +++ b/src/monitor/monitor.c @@ -1613,7 +1613,9 @@ static void monitor_sbus_connected(struct tevent_req *req) SBUS_INTERFACE(iface_service, sssd_service, SBUS_METHODS(SBUS_NO_METHODS), - SBUS_SIGNALS(SBUS_NO_SIGNALS), + SBUS_SIGNALS( + SBUS_EMITS(sssd_service, TerminateChainedRequests) + ), SBUS_PROPERTIES( SBUS_SYNC(GETTER, sssd_service, debug_level, generic_get_debug_level, NULL), SBUS_SYNC(SETTER, sssd_service, debug_level, generic_set_debug_level, NULL) @@ -1810,6 +1812,9 @@ static void mt_svc_restart(struct tevent_context *ev, if (svc->type == MT_SVC_SERVICE) { add_new_service(svc->mt_ctx, svc->name, svc->restarts + 1); } else if (svc->type == MT_SVC_PROVIDER) { + sbus_emit_service_TerminateChainedRequests(svc->mt_ctx->sbus_conn, + SSS_BUS_PATH, + svc->busname); add_new_provider(svc->mt_ctx, svc->name, svc->restarts + 1); } else { /* Invalid type? */ diff --git a/src/responder/common/responder_iface.c b/src/responder/common/responder_iface.c index ec38bfeff00..bfd19939fc1 100644 --- a/src/responder/common/responder_iface.c +++ b/src/responder/common/responder_iface.c @@ -95,6 +95,19 @@ sss_resp_reset_ncache_groups(TALLOC_CTX *mem_ctx, return EOK; } +static errno_t +sss_resp_terminate_chained_requests(TALLOC_CTX *mem_ctx, + struct sbus_request *sbus_req, + struct resp_ctx *rctx, + const char *member) +{ + DEBUG(SSSDBG_TRACE_FUNC, "Teminating outgoing chained requests for: %s\n", + member); + sbus_connection_terminate_outgoing_member(sbus_req->conn, member); + + return EOK; +} + errno_t sss_resp_register_sbus_iface(struct sbus_connection *conn, struct resp_ctx *rctx) @@ -111,7 +124,9 @@ sss_resp_register_sbus_iface(struct sbus_connection *conn, SBUS_LISTEN_SYNC(sssd_Responder_NegativeCache, ResetUsers, SSS_BUS_PATH, sss_resp_reset_ncache_users, rctx), SBUS_LISTEN_SYNC(sssd_Responder_NegativeCache, ResetGroups, - SSS_BUS_PATH, sss_resp_reset_ncache_groups, rctx) + SSS_BUS_PATH, sss_resp_reset_ncache_groups, rctx), + SBUS_LISTEN_SYNC(sssd_service, TerminateChainedRequests, + SSS_BUS_PATH, sss_resp_terminate_chained_requests, rctx) ); ret = sbus_router_listen_map(conn, listeners); diff --git a/src/sbus/connection/sbus_connection.c b/src/sbus/connection/sbus_connection.c index a5d11f67276..3c2d6642c1f 100644 --- a/src/sbus/connection/sbus_connection.c +++ b/src/sbus/connection/sbus_connection.c @@ -471,3 +471,11 @@ void sbus_connection_free(struct sbus_connection *conn) conn); } } + +void +sbus_connection_terminate_outgoing_member(struct sbus_connection *conn, + const char *member) +{ + sbus_requests_terminate_member(conn->requests->outgoing, member, + ERR_TERMINATED); +} diff --git a/src/sbus/request/sbus_request.c b/src/sbus/request/sbus_request.c index e0ea7c3a73e..845bc441fb9 100644 --- a/src/sbus/request/sbus_request.c +++ b/src/sbus/request/sbus_request.c @@ -449,6 +449,7 @@ static void sbus_incoming_request_sender_done(struct tevent_req *subreq) DBusMessageIter *write_iter = NULL; struct sbus_sender *sender; struct tevent_req *req; + const char *member = NULL; bool key_exists; errno_t ret; @@ -463,6 +464,9 @@ static void sbus_incoming_request_sender_done(struct tevent_req *subreq) } state->request->sender = talloc_steal(state->request, sender); + if (sender != NULL) { + member = sender->name; + } ret = sbus_check_access(state->conn, state->request); if (ret != EOK) { @@ -500,7 +504,7 @@ static void sbus_incoming_request_sender_done(struct tevent_req *subreq) * set a tevent callback that is triggered when the method handler is done. */ ret = sbus_requests_add(state->conn->requests->incoming, state->key, - state->conn, req, true, &key_exists); + state->conn, req, member, true, &key_exists); if (ret != EOK || key_exists) { /* Cancel the sub request. Since there was either an error or the * sub request was chained. */ @@ -617,6 +621,7 @@ sbus_outgoing_request_send(TALLOC_CTX *mem_ctx, struct sbus_outgoing_request_state *state; struct tevent_req *subreq; struct tevent_req *req; + const char *destination; bool key_exists; errno_t ret; @@ -645,6 +650,8 @@ sbus_outgoing_request_send(TALLOC_CTX *mem_ctx, } } + destination = dbus_message_get_destination(msg); + /** * We will search table to see if the same request is not already * in progress. If it is, we register ourselves for notification @@ -654,7 +661,7 @@ sbus_outgoing_request_send(TALLOC_CTX *mem_ctx, * set a tevent callback that is triggered when the method handler is done. */ ret = sbus_requests_add(conn->requests->outgoing, key, - conn, req, true, &key_exists); + conn, req, destination, true, &key_exists); if (ret != EOK) { goto done; } @@ -776,7 +783,7 @@ sbus_request_await_send(TALLOC_CTX *mem_ctx, /* Otherwise attach to this request. */ ret = sbus_requests_add(conn->requests->outgoing, key, conn, - req, false, NULL); + req, member, false, NULL); if (ret != EOK) { DEBUG(SSSDBG_CRIT_FAILURE, "Unable to attach to the request list " "[%d]: %s\n", ret, sss_strerror(ret)); diff --git a/src/sbus/request/sbus_request_hash.c b/src/sbus/request/sbus_request_hash.c index 0ddad03a87b..532c54795a4 100644 --- a/src/sbus/request/sbus_request_hash.c +++ b/src/sbus/request/sbus_request_hash.c @@ -118,6 +118,7 @@ sbus_requests_add(hash_table_t *table, const char *key, struct sbus_connection *conn, struct tevent_req *req, + const char *member, bool is_dbus, bool *_key_exists) { @@ -150,6 +151,11 @@ sbus_requests_add(hash_table_t *table, item->req = req; item->conn = conn; item->is_dbus = is_dbus; + item->member = talloc_strdup(item, member); + if (member != NULL && item->member == NULL) { + ret = ENOMEM; + goto done; + } ret = sbus_requests_attach_spies(item); if (ret != EOK) { @@ -323,3 +329,37 @@ sbus_requests_terminate_all(hash_table_t *table, talloc_free(values); } + +void +sbus_requests_terminate_member(hash_table_t *table, + const char *member, + errno_t error) +{ + struct sbus_request_list *list; + struct sbus_request_list *item; + hash_value_t *values; + unsigned long int num; + unsigned long int i; + int hret; + + hret = hash_values(table, &num, &values); + if (hret != HASH_SUCCESS) { + DEBUG(SSSDBG_CRIT_FAILURE, "Unable to get list of active requests " + "[%d]: %s\n", hret, hash_error_string(hret)); + return; + } + + for (i = 0; i < num; i++) { + list = sss_ptr_get_value(&values[i], struct sbus_request_list); + if ((member == NULL && list->member == NULL) + || (member != NULL && list->member != NULL && strcmp(member, list->member) == 0)) { + DLIST_FOR_EACH(item, list) { + sbus_requests_finish(item, error); + } + } + + sbus_requests_delete(list); + } + + talloc_free(values); +} diff --git a/src/sbus/sbus.h b/src/sbus/sbus.h index c5f564f20ac..5b82f0460a8 100644 --- a/src/sbus/sbus.h +++ b/src/sbus/sbus.h @@ -336,6 +336,16 @@ errno_t sbus_connection_add_path_map(struct sbus_connection *conn, struct sbus_path *map); +/** + * Terminate all outgoing requests for given member. + * + * @param conn An sbus connection. + * @param member D-Bus member name (destination) + */ +void +sbus_connection_terminate_outgoing_member(struct sbus_connection *conn, + const char *member); + /** * Add new signal listener to the router. * diff --git a/src/sbus/sbus_private.h b/src/sbus/sbus_private.h index a55709086bb..b27a3b4c1c4 100644 --- a/src/sbus/sbus_private.h +++ b/src/sbus/sbus_private.h @@ -431,6 +431,9 @@ struct sbus_request_list { struct tevent_req *req; struct sbus_connection *conn; + /* Member part of the key. Destination for outgoing, sender for incoming.*/ + const char *member; + bool is_invalid; bool is_dbus; @@ -462,6 +465,7 @@ sbus_requests_add(hash_table_t *table, const char *key, struct sbus_connection *conn, struct tevent_req *req, + const char *member, bool is_dbus, bool *_key_exists); @@ -484,6 +488,12 @@ void sbus_requests_terminate_all(hash_table_t *table, errno_t error); +/* Terminate requests associated with given member. */ +void +sbus_requests_terminate_member(hash_table_t *table, + const char *member, + errno_t error); + /* Create new sbus request. */ struct sbus_request * sbus_request_create(TALLOC_CTX *mem_ctx, diff --git a/src/sss_iface/sbus_sss_client_async.c b/src/sss_iface/sbus_sss_client_async.c index 1391d8de0ea..1fa4d4ab7ac 100644 --- a/src/sss_iface/sbus_sss_client_async.c +++ b/src/sss_iface/sbus_sss_client_async.c @@ -2376,6 +2376,16 @@ sbus_emit_resp_negcache_ResetUsers "sssd.Responder.NegativeCache", "ResetUsers"); } +void +sbus_emit_monitor_SetActive + (struct sbus_connection *conn, + const char *object_path, + const char * arg_name) +{ + sbus_emit_signal_s(conn, object_path, + "sssd.monitor", "SetActive", arg_name); +} + void sbus_emit_nss_memcache_InvalidateAllGroups (struct sbus_connection *conn, @@ -2412,3 +2422,13 @@ sbus_emit_nss_memcache_InvalidateGroupById sbus_emit_signal_u(conn, object_path, "sssd.nss.MemoryCache", "InvalidateGroupById", arg_gid); } + +void +sbus_emit_service_TerminateChainedRequests + (struct sbus_connection *conn, + const char *object_path, + const char * arg_name) +{ + sbus_emit_signal_s(conn, object_path, + "sssd.service", "TerminateChainedRequests", arg_name); +} diff --git a/src/sss_iface/sbus_sss_client_async.h b/src/sss_iface/sbus_sss_client_async.h index d400cb4040f..b339110d364 100644 --- a/src/sss_iface/sbus_sss_client_async.h +++ b/src/sss_iface/sbus_sss_client_async.h @@ -428,6 +428,12 @@ sbus_emit_resp_negcache_ResetUsers (struct sbus_connection *conn, const char *object_path); +void +sbus_emit_monitor_SetActive + (struct sbus_connection *conn, + const char *object_path, + const char * arg_name); + void sbus_emit_nss_memcache_InvalidateAllGroups (struct sbus_connection *conn, @@ -449,4 +455,10 @@ sbus_emit_nss_memcache_InvalidateGroupById const char *object_path, uint32_t arg_gid); +void +sbus_emit_service_TerminateChainedRequests + (struct sbus_connection *conn, + const char *object_path, + const char * arg_name); + #endif /* _SBUS_SSS_CLIENT_ASYNC_H_ */ diff --git a/src/sss_iface/sbus_sss_interface.h b/src/sss_iface/sbus_sss_interface.h index 138ced6276d..e5d09af335b 100644 --- a/src/sss_iface/sbus_sss_interface.h +++ b/src/sss_iface/sbus_sss_interface.h @@ -677,6 +677,30 @@ (handler_send), (handler_recv), (data)); \ }) +/* Signal: sssd.monitor.SetActive */ +#define SBUS_SIGNAL_EMITS_sssd_monitor_SetActive() ({ \ + sbus_signal("SetActive", \ + _sbus_sss_args_sssd_monitor_SetActive, \ + NULL); \ +}) + +#define SBUS_SIGNAL_SYNC_sssd_monitor_SetActive(path, handler, data) ({ \ + SBUS_CHECK_SYNC((handler), (data), const char *); \ + sbus_listener_sync("sssd.monitor", "SetActive", (path), \ + _sbus_sss_invoke_in_s_out__send, \ + NULL, \ + (handler), (data)); \ +}) + +#define SBUS_SIGNAL_ASYNC_sssd_monitor_SetActive(path, handler_send, handler_recv, data) ({ \ + SBUS_CHECK_SEND((handler_send), (data), const char *); \ + SBUS_CHECK_RECV((handler_recv)); \ + sbus_listener_async("sssd.monitor", "SetActive", (path), \ + _sbus_sss_invoke_in_s_out__send, \ + NULL, \ + (handler_send), (handler_recv), (data)); \ +}) + /* Interface: sssd.nss.MemoryCache */ #define SBUS_IFACE_sssd_nss_MemoryCache(methods, signals, properties) ({ \ sbus_interface("sssd.nss.MemoryCache", NULL, \ @@ -961,6 +985,30 @@ (handler_send), (handler_recv), (data)); \ }) +/* Signal: sssd.service.TerminateChainedRequests */ +#define SBUS_SIGNAL_EMITS_sssd_service_TerminateChainedRequests() ({ \ + sbus_signal("TerminateChainedRequests", \ + _sbus_sss_args_sssd_service_TerminateChainedRequests, \ + NULL); \ +}) + +#define SBUS_SIGNAL_SYNC_sssd_service_TerminateChainedRequests(path, handler, data) ({ \ + SBUS_CHECK_SYNC((handler), (data), const char *); \ + sbus_listener_sync("sssd.service", "TerminateChainedRequests", (path), \ + _sbus_sss_invoke_in_s_out__send, \ + NULL, \ + (handler), (data)); \ +}) + +#define SBUS_SIGNAL_ASYNC_sssd_service_TerminateChainedRequests(path, handler_send, handler_recv, data) ({ \ + SBUS_CHECK_SEND((handler_send), (data), const char *); \ + SBUS_CHECK_RECV((handler_recv)); \ + sbus_listener_async("sssd.service", "TerminateChainedRequests", (path), \ + _sbus_sss_invoke_in_s_out__send, \ + NULL, \ + (handler_send), (handler_recv), (data)); \ +}) + /* Property: sssd.service.debug_level */ #define SBUS_GETTER_SYNC_sssd_service_debug_level(handler, data) ({ \ SBUS_CHECK_SYNC((handler), (data), uint32_t*); \ diff --git a/src/sss_iface/sbus_sss_symbols.c b/src/sss_iface/sbus_sss_symbols.c index 0219f370d34..f5bb2570cf4 100644 --- a/src/sss_iface/sbus_sss_symbols.c +++ b/src/sss_iface/sbus_sss_symbols.c @@ -339,6 +339,12 @@ _sbus_sss_args_sssd_monitor_RegisterService = { } }; +const struct sbus_argument +_sbus_sss_args_sssd_monitor_SetActive[] = { + {.type = "s", .name = "name"}, + {NULL} +}; + const struct sbus_method_arguments _sbus_sss_args_sssd_nss_MemoryCache_UpdateInitgroups = { .input = (const struct sbus_argument[]){ @@ -442,3 +448,9 @@ _sbus_sss_args_sssd_service_sysbusReconnect = { {NULL} } }; + +const struct sbus_argument +_sbus_sss_args_sssd_service_TerminateChainedRequests[] = { + {.type = "s", .name = "name"}, + {NULL} +}; diff --git a/src/sss_iface/sbus_sss_symbols.h b/src/sss_iface/sbus_sss_symbols.h index ab9969b736c..0b44596e5d1 100644 --- a/src/sss_iface/sbus_sss_symbols.h +++ b/src/sss_iface/sbus_sss_symbols.h @@ -100,6 +100,9 @@ _sbus_sss_args_sssd_dataprovider_sudoHandler; extern const struct sbus_method_arguments _sbus_sss_args_sssd_monitor_RegisterService; +extern const struct sbus_argument +_sbus_sss_args_sssd_monitor_SetActive[]; + extern const struct sbus_method_arguments _sbus_sss_args_sssd_nss_MemoryCache_UpdateInitgroups; @@ -136,4 +139,7 @@ _sbus_sss_args_sssd_service_rotateLogs; extern const struct sbus_method_arguments _sbus_sss_args_sssd_service_sysbusReconnect; +extern const struct sbus_argument +_sbus_sss_args_sssd_service_TerminateChainedRequests[]; + #endif /* _SBUS_SSS_SYMBOLS_H_ */ diff --git a/src/sss_iface/sss_iface.xml b/src/sss_iface/sss_iface.xml index 02b98789de4..4425158a8a4 100644 --- a/src/sss_iface/sss_iface.xml +++ b/src/sss_iface/sss_iface.xml @@ -10,6 +10,9 @@ + + + @@ -26,6 +29,9 @@ + + + diff --git a/src/tests/system/tests/test_identity.py b/src/tests/system/tests/test_identity.py index bf50a7d0403..e92d10c016c 100644 --- a/src/tests/system/tests/test_identity.py +++ b/src/tests/system/tests/test_identity.py @@ -12,7 +12,8 @@ from sssd_test_framework.roles.client import Client from sssd_test_framework.roles.generic import GenericADProvider, GenericProvider from sssd_test_framework.roles.ipa import IPA -from sssd_test_framework.topology import KnownTopologyGroup +from sssd_test_framework.roles.ldap import LDAP +from sssd_test_framework.topology import KnownTopology, KnownTopologyGroup @pytest.mark.importance("critical") @@ -681,3 +682,46 @@ def test_identity__lookup_when_auto_private_groups_is_set_to_hybrid(client: Clie assert result is not None, "User 'user_group_gid' not found!" assert result.gid == 555555, "gid does not match expected value!" assert client.tools.getent.group(555555) is not None, "auto private group not found!" + + +@pytest.mark.importance("low") +@pytest.mark.topology(KnownTopology.LDAP) +def test_identity__lookup_when_backend_restarts(client: Client, ldap: LDAP): + """ + :title: Look up user when backend is restarted with previous lookup unfinished + :description: + If there is an active lookup for a user and the backend is restarted + before this lookup is finished, the next lookup of the same user after + the restart must not timeout. + :setup: + 1. Add a user "tuser" + 2. Start SSSD + :steps: + 1. Add 10s network traffic delay to the LDAP host + 2. Lookup "tuser" asynchronously + 3. Kill sssd_be with SIGKILL so it is restarted + 4. Remove the network traffic delay + 5. Lookup of "tuser" must yield the user and not timeout + :expectedresults: + 1. Network traffic is delayed + 2. Lookup hangs, does not finish and waits for a timeout + 3. The backend process is restarted + 4. Network traffic is no longer delayed + 5. User lookup returns the user immediately + :customerscenario: False + """ + ldap.user("tuser").add() + + client.sssd.start() + + # Add a delay so the next lookup will hang + client.tc.add_delay(ldap, "10s") + client.host.conn.async_run("getent passwd tuser") + + # Kill backend and remove the delay + client.host.conn.run("kill -KILL $(pidof sssd_be)") + client.tc.remove_delay(ldap) + + # The next lookup should not timeout + result = client.tools.wait_for_condition("getent passwd tuser", timeout=5) + assert "tuser" in result.stdout, "tuser was not found"