summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2011-07-28 15:32:30 -0400
committerStephen Gallagher <sgallagh@redhat.com>2012-06-22 11:00:33 -0400
commitd5fdf2d1170ff40f3b6d76e729aa56bd783202ee (patch)
treefa5a3e7fa478c9ff8a369e105b7e427193b979c8
parentc08c6c7a131fcb0546c70e187c44fc2e6449e8ce (diff)
downloadsssd-d5fdf2d1170ff40f3b6d76e729aa56bd783202ee.tar.gz
sssd-d5fdf2d1170ff40f3b6d76e729aa56bd783202ee.tar.xz
sssd-d5fdf2d1170ff40f3b6d76e729aa56bd783202ee.zip
Add support for terminating idle connections
Converge accept_fd_handler and accept_priv_fd_handler These two functions were almost identical. Better to maintain them as a single function. Set return errno to the value prior to calling close(). Log message if close() fails in destructor. Do not send SIGPIPE on disconnection Note we set MSG_NOSIGNAL to avoid having to fiddle with signal masks but also do not want to die in case SIGPIPE gets raised and the application does not handle it. Add support for terminating idle connections Conflicts: src/responder/common/responder.h src/responder/common/responder_common.c
-rw-r--r--src/responder/common/responder.h2
-rw-r--r--src/responder/common/responder_common.c206
-rw-r--r--src/sss_client/common.c31
3 files changed, 147 insertions, 92 deletions
diff --git a/src/responder/common/responder.h b/src/responder/common/responder.h
index c17ccdf1c..a3e567ac8 100644
--- a/src/responder/common/responder.h
+++ b/src/responder/common/responder.h
@@ -121,6 +121,8 @@ struct cli_ctx {
int netgrent_cur;
time_t pam_timeout;
+
+ struct tevent_timer *idle;
};
struct sss_cmd_table {
diff --git a/src/responder/common/responder_common.c b/src/responder/common/responder_common.c
index 261d91fb7..488e22a5a 100644
--- a/src/responder/common/responder_common.c
+++ b/src/responder/common/responder_common.c
@@ -90,7 +90,18 @@ static errno_t set_close_on_exec(int fd)
static int client_destructor(struct cli_ctx *ctx)
{
- if (ctx->cfd > 0) close(ctx->cfd);
+ errno_t ret;
+
+ if ((ctx->cfd > 0) && close(ctx->cfd) < 0) {
+ ret = errno;
+ DEBUG(1,
+ ("Failed to close fd [%d]: [%s]\n",
+ ctx->cfd, strerror(ret)));
+ }
+
+ DEBUG(8,
+ ("Terminated client [%p][%d]\n",
+ ctx, ctx->cfd));
return 0;
}
@@ -211,12 +222,24 @@ static void client_recv(struct cli_ctx *cctx)
return;
}
+static errno_t reset_idle_timer(struct cli_ctx *cctx);
+
static void client_fd_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *ptr)
{
+ errno_t ret;
struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);
+ /* Always reset the idle timer on any activity */
+ ret = reset_idle_timer(cctx);
+ if (ret != EOK) {
+ DEBUG(1,
+ ("Could not create idle timer for client. "
+ "This connection may not auto-terminate\n"));
+ /* Non-fatal, continue */
+ }
+
if (flags & TEVENT_FD_READ) {
client_recv(cctx);
return;
@@ -227,59 +250,72 @@ static void client_fd_handler(struct tevent_context *ev,
}
}
-/* TODO: this is a copy of accept_fd_handler, maybe both can be put into on
- * handler. */
-static void accept_priv_fd_handler(struct tevent_context *ev,
+struct accept_fd_ctx {
+ struct resp_ctx *rctx;
+ bool is_private;
+};
+
+static void idle_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *data);
+
+static void accept_fd_handler(struct tevent_context *ev,
struct tevent_fd *fde,
uint16_t flags, void *ptr)
{
/* accept and attach new event handler */
- struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
+ struct accept_fd_ctx *accept_ctx =
+ talloc_get_type(ptr, struct accept_fd_ctx);
+ struct resp_ctx *rctx = accept_ctx->rctx;
struct cli_ctx *cctx;
socklen_t len;
struct stat stat_buf;
int ret;
+ int fd = accept_ctx->is_private ? rctx->priv_lfd : rctx->lfd;
+ int client_fd;
+
+ if (accept_ctx->is_private) {
+ ret = stat(rctx->priv_sock_name, &stat_buf);
+ if (ret == -1) {
+ DEBUG(1, ("stat on privileged pipe failed: [%d][%s].\n", errno,
+ strerror(errno)));
+ return;
+ }
- ret = stat(rctx->priv_sock_name, &stat_buf);
- if (ret == -1) {
- DEBUG(1, ("stat on privileged pipe failed: [%d][%s].\n", errno,
- strerror(errno)));
- return;
- }
-
- if ( ! (stat_buf.st_uid == 0 && stat_buf.st_gid == 0 &&
- (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
- DEBUG(1, ("privileged pipe has an illegal status.\n"));
-/* TODO: what is the best response to this condition? Terminate? */
- return;
+ if ( ! (stat_buf.st_uid == 0 && stat_buf.st_gid == 0 &&
+ (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
+ DEBUG(1, ("privileged pipe has an illegal status.\n"));
+ /* TODO: what is the best response to this condition? Terminate? */
+ return;
+ }
}
-
cctx = talloc_zero(rctx, struct cli_ctx);
if (!cctx) {
struct sockaddr_un addr;
- int fd;
- DEBUG(0, ("Out of memory trying to setup client context on privileged pipe!\n"));
+ DEBUG(0, ("Out of memory trying to setup client context%s!\n",
+ accept_ctx->is_private ? " on privileged pipe": ""));
/* accept and close to signal the client we have a problem */
memset(&addr, 0, sizeof(addr));
len = sizeof(addr);
- fd = accept(rctx->priv_lfd, (struct sockaddr *)&addr, &len);
- if (fd == -1) {
+ client_fd = accept(fd, (struct sockaddr *)&addr, &len);
+ if (client_fd == -1) {
return;
}
- close(fd);
+ close(client_fd);
return;
}
len = sizeof(cctx->addr);
- cctx->cfd = accept(rctx->priv_lfd, (struct sockaddr *)&cctx->addr, &len);
+ cctx->cfd = accept(fd, (struct sockaddr *)&cctx->addr, &len);
if (cctx->cfd == -1) {
DEBUG(1, ("Accept failed [%s]\n", strerror(errno)));
talloc_free(cctx);
return;
}
- cctx->priv = 1;
+ cctx->priv = accept_ctx->is_private;
ret = get_client_cred(cctx);
if (ret != EOK) {
@@ -292,7 +328,8 @@ static void accept_priv_fd_handler(struct tevent_context *ev,
if (!cctx->cfde) {
close(cctx->cfd);
talloc_free(cctx);
- DEBUG(2, ("Failed to queue client handler on privileged pipe\n"));
+ DEBUG(2, ("Failed to queue client handler%\n",
+ accept_ctx->is_private ? " on privileged pipe" : ""));
}
cctx->ev = ev;
@@ -300,65 +337,18 @@ static void accept_priv_fd_handler(struct tevent_context *ev,
talloc_set_destructor(cctx, client_destructor);
- DEBUG(4, ("Client connected to privileged pipe!\n"));
-
- return;
-}
-
-static void accept_fd_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags, void *ptr)
-{
- /* accept and attach new event handler */
- struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
- struct cli_ctx *cctx;
- socklen_t len;
- int ret;
-
- cctx = talloc_zero(rctx, struct cli_ctx);
- if (!cctx) {
- struct sockaddr_un addr;
- int fd;
- DEBUG(0, ("Out of memory trying to setup client context!\n"));
- /* accept and close to signal the client we have a problem */
- memset(&addr, 0, sizeof(addr));
- len = sizeof(addr);
- fd = accept(rctx->lfd, (struct sockaddr *)&addr, &len);
- if (fd == -1) {
- return;
- }
- close(fd);
- return;
- }
-
- len = sizeof(cctx->addr);
- cctx->cfd = accept(rctx->lfd, (struct sockaddr *)&cctx->addr, &len);
- if (cctx->cfd == -1) {
- DEBUG(1, ("Accept failed [%s]\n", strerror(errno)));
- talloc_free(cctx);
- return;
- }
-
- ret = get_client_cred(cctx);
+ /* Set up the idle timer */
+ ret = reset_idle_timer(cctx);
if (ret != EOK) {
- DEBUG(2, ("get_client_cred failed, "
- "client cred may not be available.\n"));
- }
-
- cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
- TEVENT_FD_READ, client_fd_handler, cctx);
- if (!cctx->cfde) {
- close(cctx->cfd);
- talloc_free(cctx);
- DEBUG(2, ("Failed to queue client handler\n"));
+ DEBUG(1,
+ ("Could not create idle timer for client. "
+ "This connection may not auto-terminate\n"));
+ /* Non-fatal, continue */
}
- cctx->ev = ev;
- cctx->rctx = rctx;
-
- talloc_set_destructor(cctx, client_destructor);
-
- DEBUG(4, ("Client connected!\n"));
+ DEBUG(6,
+ ("Client connected%s!\n",
+ accept_ctx->is_private ? " to privileged pipe" : ""));
return;
}
@@ -395,6 +385,41 @@ static int sss_monitor_init(struct resp_ctx *rctx,
return EOK;
}
+static errno_t reset_idle_timer(struct cli_ctx *cctx)
+{
+ struct timeval tv;
+
+ /* TODO: make this configurable */
+ tv = tevent_timeval_current_ofs(60, 0);
+
+ talloc_zfree(cctx->idle);
+
+ cctx->idle = tevent_add_timer(cctx->ev, cctx, tv, idle_handler, cctx);
+ if (!cctx->idle) return ENOMEM;
+
+ DEBUG(9,
+ ("Idle timer re-set for client [%p][%d]\n",
+ cctx, cctx->cfd));
+
+ return EOK;
+}
+
+static void idle_handler(struct tevent_context *ev,
+ struct tevent_timer *te,
+ struct timeval current_time,
+ void *data)
+{
+ /* This connection is idle. Terminate it */
+ struct cli_ctx *cctx =
+ talloc_get_type(data, struct cli_ctx);
+
+ DEBUG(9,
+ ("Terminating idle client [%p][%d]\n",
+ cctx, cctx->cfd));
+
+ /* The cli_ctx destructor will handle the rest */
+ talloc_free(cctx);
+}
static int sss_dp_init(struct resp_ctx *rctx,
struct sbus_interface *intf,
@@ -445,6 +470,7 @@ static int set_unix_socket(struct resp_ctx *rctx)
{
struct sockaddr_un addr;
errno_t ret;
+ struct accept_fd_ctx *accept_ctx;
/* for future use */
#if 0
@@ -519,8 +545,14 @@ static int set_unix_socket(struct resp_ctx *rctx)
goto failed;
}
+ accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
+ if(!accept_ctx) goto failed;
+ accept_ctx->rctx = rctx;
+ accept_ctx->is_private = false;
+
rctx->lfde = tevent_add_fd(rctx->ev, rctx, rctx->lfd,
- TEVENT_FD_READ, accept_fd_handler, rctx);
+ TEVENT_FD_READ, accept_fd_handler,
+ accept_ctx);
if (!rctx->lfde) {
DEBUG(0, ("Failed to queue handler on pipe\n"));
goto failed;
@@ -563,8 +595,14 @@ static int set_unix_socket(struct resp_ctx *rctx)
goto failed;
}
+ accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
+ if(!accept_ctx) goto failed;
+ accept_ctx->rctx = rctx;
+ accept_ctx->is_private = true;
+
rctx->priv_lfde = tevent_add_fd(rctx->ev, rctx, rctx->priv_lfd,
- TEVENT_FD_READ, accept_priv_fd_handler, rctx);
+ TEVENT_FD_READ, accept_fd_handler,
+ accept_ctx);
if (!rctx->priv_lfde) {
DEBUG(0, ("Failed to queue handler on privileged pipe\n"));
goto failed;
diff --git a/src/sss_client/common.c b/src/sss_client/common.c
index 5f6af418a..624e93294 100644
--- a/src/sss_client/common.c
+++ b/src/sss_client/common.c
@@ -50,6 +50,19 @@
#include <pthread.h>
#endif
+/*
+* Note we set MSG_NOSIGNAL to avoid
+* having to fiddle with signal masks
+* but also do not want to die in case
+* SIGPIPE gets raised and the application
+* does not handle it.
+*/
+#ifdef MSG_NOSIGNAL
+#define SSS_DEFAULT_WRITE_FLAGS MSG_NOSIGNAL
+#else
+#define SSS_DEFAULT_WRITE_FLAGS 0
+#endif
+
/* common functions */
int sss_cli_sd = -1; /* the sss client socket descriptor */
@@ -134,14 +147,16 @@ static enum nss_status sss_nss_send_req(enum sss_cli_command cmd,
errno = 0;
if (datasent < SSS_NSS_HEADER_SIZE) {
- res = write(sss_cli_sd,
- (char *)header + datasent,
- SSS_NSS_HEADER_SIZE - datasent);
+ res = send(sss_cli_sd,
+ (char *)header + datasent,
+ SSS_NSS_HEADER_SIZE - datasent,
+ SSS_DEFAULT_WRITE_FLAGS);
} else {
rdsent = datasent - SSS_NSS_HEADER_SIZE;
- res = write(sss_cli_sd,
- (const char *)rd->data + rdsent,
- rd->len - rdsent);
+ res = send(sss_cli_sd,
+ (const char *)rd->data + rdsent,
+ rd->len - rdsent,
+ SSS_DEFAULT_WRITE_FLAGS);
}
error = errno;
@@ -155,7 +170,7 @@ static enum nss_status sss_nss_send_req(enum sss_cli_command cmd,
/* Write failed */
sss_cli_close_socket();
- *errnop = errno;
+ *errnop = error;
return NSS_STATUS_UNAVAIL;
}
@@ -265,7 +280,7 @@ static enum nss_status sss_nss_recv_rep(enum sss_cli_command cmd,
* through. */
sss_cli_close_socket();
- *errnop = errno;
+ *errnop = error;
ret = NSS_STATUS_UNAVAIL;
goto failed;
}