From 43d4982ed6e578fbb489da96d8fd71fcb5e6cd2a Mon Sep 17 00:00:00 2001 From: Lukas Slebodnik Date: Wed, 17 Feb 2016 15:21:55 +0100 Subject: [PATCH] CLIENT: Retry request after EPIPE We have a function sss_cli_check_socket which checks socket in client code. The socket is reopened in case of some issues e.g. responder terminated connections ... We use syscall poll for checking status of socket. It's not 100% reliable method because there is still chance that responder will terminate socket after this check. Here is a schema of sss_*_make_request functions: sss_cli_check_socket sss_cli_make_request_nochecks { sss_cli_send_req { poll send } sss_cli_recv_rep { poll read } } The syscall pool does not return EPIPE directly but we convert special revents from poll to EPIPE. As it was mentioned earlier, checking of socket in the sss_cli_check_socket is not 100% reliable. It can happen very rarely due to TOCTOU issue (Time of check to time of use) We can return EPIPE from the sss_cli_make_request_nochecks function in case of failure in poll in sss_cli_send_req. The send function in sss_cli_send_req can also return EPIPE is responder close socket in the same time. The send function can succeed in sss_cli_send_req but it does not mean that responder read the message. It can happen that timer for closing socket can be handled before reading a message. Therefore there is a still a chance that we might return EPIPE in case of failure in poll in sss_cli_recv_rep. Therefore we need to reconnect to responder in case of EPIPE returned from sss_cli_make_request_nochecks and try to do request one more time. Resolves: https://fedorahosted.org/sssd/ticket/2922 --- src/sss_client/common.c | 77 ++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 17 deletions(-) diff --git a/src/sss_client/common.c b/src/sss_client/common.c index 0d9106a..68f4035 100644 --- a/src/sss_client/common.c +++ b/src/sss_client/common.c @@ -734,6 +734,22 @@ enum nss_status sss_nss_make_request(enum sss_cli_command cmd, } ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + if (ret == SSS_STATUS_UNAVAIL && *errnop == EPIPE) { + /* try reopen socket */ + ret = sss_cli_check_socket(errnop, SSS_NSS_SOCKET_NAME); + if (ret != SSS_STATUS_SUCCESS) { +#ifdef NONSTANDARD_SSS_NSS_BEHAVIOUR + *errnop = 0; + errno = 0; + return NSS_STATUS_NOTFOUND; +#else + return NSS_STATUS_UNAVAIL; +#endif + } + + /* and make request one more time */ + ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + } switch (ret) { case SSS_STATUS_TRYAGAIN: return NSS_STATUS_TRYAGAIN; @@ -784,6 +800,16 @@ int sss_pac_make_request(enum sss_cli_command cmd, } ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + if (ret == SSS_STATUS_UNAVAIL && *errnop == EPIPE) { + /* try reopen socket */ + ret = sss_cli_check_socket(errnop, SSS_PAC_SOCKET_NAME); + if (ret != SSS_STATUS_SUCCESS) { + return NSS_STATUS_UNAVAIL; + } + + /* and make request one more time */ + ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + } switch (ret) { case SSS_STATUS_TRYAGAIN: return NSS_STATUS_TRYAGAIN; @@ -910,19 +936,44 @@ void sss_pam_close_fd(void) sss_pam_unlock(); } -int sss_sudo_make_request(enum sss_cli_command cmd, - struct sss_cli_req_data *rd, - uint8_t **repbuf, size_t *replen, - int *errnop) +static enum sss_status +sss_cli_make_request_with_checks(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, + uint8_t **repbuf, size_t *replen, + int *errnop, + const char *socket_name) { enum sss_status ret = SSS_STATUS_UNAVAIL; - ret = sss_cli_check_socket(errnop, SSS_SUDO_SOCKET_NAME); + ret = sss_cli_check_socket(errnop, socket_name); if (ret != SSS_STATUS_SUCCESS) { return SSS_STATUS_UNAVAIL; } ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + if (ret == SSS_STATUS_UNAVAIL && *errnop == EPIPE) { + /* try reopen socket */ + ret = sss_cli_check_socket(errnop, socket_name); + if (ret != SSS_STATUS_SUCCESS) { + return SSS_STATUS_UNAVAIL; + } + + /* and make request one more time */ + ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + } + + return ret; +} + +int sss_sudo_make_request(enum sss_cli_command cmd, + struct sss_cli_req_data *rd, + uint8_t **repbuf, size_t *replen, + int *errnop) +{ + enum sss_status ret = SSS_STATUS_UNAVAIL; + + ret = sss_cli_make_request_with_checks(cmd, rd, repbuf, replen, errnop, + SSS_SUDO_SOCKET_NAME); return ret; } @@ -934,12 +985,8 @@ int sss_autofs_make_request(enum sss_cli_command cmd, { enum sss_status ret = SSS_STATUS_UNAVAIL; - ret = sss_cli_check_socket(errnop, SSS_AUTOFS_SOCKET_NAME); - if (ret != SSS_STATUS_SUCCESS) { - return SSS_STATUS_UNAVAIL; - } - - ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + ret = sss_cli_make_request_with_checks(cmd, rd, repbuf, replen, errnop, + SSS_AUTOFS_SOCKET_NAME); return ret; } @@ -951,12 +998,8 @@ int sss_ssh_make_request(enum sss_cli_command cmd, { enum sss_status ret = SSS_STATUS_UNAVAIL; - ret = sss_cli_check_socket(errnop, SSS_SSH_SOCKET_NAME); - if (ret != SSS_STATUS_SUCCESS) { - return SSS_STATUS_UNAVAIL; - } - - ret = sss_cli_make_request_nochecks(cmd, rd, repbuf, replen, errnop); + ret = sss_cli_make_request_with_checks(cmd, rd, repbuf, replen, errnop, + SSS_SSH_SOCKET_NAME); return ret; } -- 2.5.0