URL: https://github.com/SSSD/sssd/pull/32
Author: fidencio
 Title: #32: Requesting a pull to SSSD:master from fidencio:wip/#3138
Action: opened

PR body:
"""
This patch series is intended to solve #3138 by adding a new service
that updates the confdb. As part of the series this service is used by
secrets service.

I only ran CI locally and the two secrets tests have been failing. /o\

Also, I've noticed some weird behavior, where the sssd-update-confdb
service starts for apparently no reason, when upgrading fedora
packages.

Anyways, these pieces of code really need some detailed review as it
was the first time I've been "seriously" playing with TEvent requests.
So, please, consider it more like an RFC than a well finished and
polished code.

Best Regards,
"""

To pull the PR as Git branch:
git remote add ghsssd https://github.com/SSSD/sssd
git fetch ghsssd pull/32/head:pr32
git checkout pr32
From d3816e7d72eec4967f6bc253e67fc976bf4ae59e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com>
Date: Fri, 16 Sep 2016 17:32:12 +0200
Subject: [PATCH 1/3] UPDATE_CONFDB: Add a new service to refresh configuration
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Currently confdb is only refreshed when sssd starts. It may cause
issues with socket-activated services (like sssd-secrets) that may end
up reading a not up-to-date configuration from confdb.

This socket-activated service does a very simple task: writes the
configuration to confdb and exists.

The way it's implemented now is:
- receives a single byte from the service that wants to have the
  configuration file updated;
- writes the configuration to confdb;
- sends a single byte back to the service;
- exits;

For now it's being placed where it is simply for a lack of a better
place. And it's being built only when sssd-secrets is built because, at
least for now, sssd-secrets will be the only responder using it.

Tests for this new service are needed as well, but are not implemented
yet (they will be part of a later on series).

Last note is that it *must* be executed as root in order to read
sssd.conf and write the confdb file.

Related:
https://fedorahosted.org/sssd/ticket/3138

Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com>
---
 Makefile.am                                    |  27 +++
 contrib/sssd.spec.in                           |   7 +
 src/confdb/confdb.h                            |   2 +
 src/responder/update_confdb/update_confdb.c    | 309 +++++++++++++++++++++++++
 src/sysv/systemd/sssd-update-confdb.service.in |   8 +
 src/sysv/systemd/sssd-update-confdb.socket.in  |   8 +
 6 files changed, 361 insertions(+)
 create mode 100644 src/responder/update_confdb/update_confdb.c
 create mode 100644 src/sysv/systemd/sssd-update-confdb.service.in
 create mode 100644 src/sysv/systemd/sssd-update-confdb.socket.in

diff --git a/Makefile.am b/Makefile.am
index 17c5f26..18a72ca 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,6 +175,7 @@ endif
 endif
 if BUILD_SECRETS
 sssdlibexec_PROGRAMS += sssd_secrets
+sssdlibexec_PROGRAMS += sssd_update_confdb
 endif
 
 if BUILD_PAC_RESPONDER
@@ -473,6 +474,7 @@ AM_CPPFLAGS = \
     -DSSS_PAC_SOCKET_NAME=\"$(pipepath)/pac\" \
     -DSSS_PAM_PRIV_SOCKET_NAME=\"$(pipepath)/private/pam\" \
     -DSSS_SEC_SOCKET_NAME=\"$(runstatedir)/secrets.socket\" \
+    -DSSS_UPDATE_CONFDB_SOCKET_NAME=\"$(runstatedir)/update-confdb.socket\" \
     -DSSS_SUDO_SOCKET_NAME=\"$(pipepath)/sudo\" \
     -DSSS_AUTOFS_SOCKET_NAME=\"$(pipepath)/autofs\" \
     -DSSS_SSH_SOCKET_NAME=\"$(pipepath)/ssh\" \
@@ -1391,6 +1393,17 @@ sssd_secrets_LDADD = \
     $(CARES_LIBS) \
     $(SSSD_INTERNAL_LTLIBS) \
     $(NULL)
+
+sssd_update_confdb_SOURCES = \
+    src/responder/update_confdb/update_confdb.c \
+    $(SSSD_RESPONDER_OBJ) \
+    $(SSSD_TOOLS_OBJ) \
+    $(NULL)
+sssd_update_confdb_LDADD = \
+    $(SSSD_LIBS) \
+    $(SYSTEMD_DAEMON_LIBS) \
+    $(SSSD_INTERNAL_LTLIBS) \
+    $(NULL)
 endif
 
 sssd_be_SOURCES = \
@@ -3895,6 +3908,8 @@ if HAVE_SYSTEMD_UNIT
         src/sysv/systemd/sssd.service \
         src/sysv/systemd/sssd-secrets.socket \
         src/sysv/systemd/sssd-secrets.service \
+        src/sysv/systemd/sssd-update-confdb.socket \
+        src/sysv/systemd/sssd-update-confdb.service \
         $(NULL)
 if WITH_JOURNALD
     systemdconf_DATA += \
@@ -3948,6 +3963,8 @@ EXTRA_DIST += \
     src/sysv/systemd/journal.conf.in \
     src/sysv/systemd/sssd-secrets.socket.in \
     src/sysv/systemd/sssd-secrets.service.in \
+    src/sysv/systemd/sssd-update-confdb.socket.in \
+    src/sysv/systemd/sssd-update-confdb.service.in \
     $(NULL)
 
 src/sysv/systemd/sssd.service: src/sysv/systemd/sssd.service.in Makefile
@@ -3966,6 +3983,14 @@ src/sysv/systemd/sssd-secrets.service: src/sysv/systemd/sssd-secrets.service.in
 	@$(MKDIR_P) src/sysv/systemd/
 	$(replace_script)
 
+src/sysv/systemd/sssd-update-confdb.socket: src/sysv/systemd/sssd-update-confdb.socket.in Makefile
+	@$(MKDIR_P) src/sysv/systemd/
+	$(replace_script)
+
+src/sysv/systemd/sssd-update-confdb.service: src/sysv/systemd/sssd-update-confdb.service.in Makefile
+	@$(MKDIR_P) src/sysv/systemd/
+	$(replace_script)
+
 SSSD_USER_DIRS = \
     $(DESTDIR)$(dbpath) \
     $(DESTDIR)$(keytabdir) \
@@ -4183,6 +4208,8 @@ endif
 	rm -f $(builddir)/src/sysv/systemd/sssd.service
 	rm -f $(builddir)/src/sysv/systemd/sssd-secrets.socket
 	rm -f $(builddir)/src/sysv/systemd/sssd-secrets.service
+	rm -f $(builddir)/src/sysv/systemd/sssd-update-confdb.socket
+	rm -f $(builddir)/src/sysv/systemd/sssd-update-confdb.service
 	rm -f $(builddir)/src/sysv/systemd/journal.conf
 
 CLEANFILES += *.X */*.X */*/*.X
diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 1f79ca7..9e709b1 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -749,6 +749,8 @@ done
 %{_unitdir}/sssd.service
 %{_unitdir}/sssd-secrets.socket
 %{_unitdir}/sssd-secrets.service
+%{_unitdir}/sssd-update-confdb.socket
+%{_unitdir}/sssd-update-confdb.service
 %else
 %{_initrddir}/%{name}
 %endif
@@ -761,6 +763,7 @@ done
 %{_libexecdir}/%{servicename}/sssd_secrets
 %{_libexecdir}/%{servicename}/sssd_ssh
 %{_libexecdir}/%{servicename}/sssd_sudo
+%{_libexecdir}/%{servicename}/sssd_update_confdb
 %{_libexecdir}/%{servicename}/p11_child
 
 %dir %{_libdir}/%{name}
@@ -1082,15 +1085,19 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us
 %post common
 %systemd_post sssd.service
 %systemd_post sssd-secrets.socket
+%systemd_post sssd-update-confdb.socket
 
 %preun common
 %systemd_preun sssd.service
 %systemd_preun sssd-secrets.socket
+%systemd_preun sssd-update-confdb.socket
 
 %postun common
 %systemd_postun_with_restart sssd.service
 %systemd_postun_with_restart sssd-secrets.socket
 %systemd_postun_with_restart sssd-secrets.service
+%systemd_postun_with_restart sssd-update-confdb.socket
+%systemd_postun_with_restart sssd-update-confdb.service
 
 %else
 # sysv
diff --git a/src/confdb/confdb.h b/src/confdb/confdb.h
index 36a2f21..3f2b9d6 100644
--- a/src/confdb/confdb.h
+++ b/src/confdb/confdb.h
@@ -224,6 +224,8 @@
 /* Secrets Service */
 #define CONFDB_SEC_CONF_ENTRY "config/secrets"
 
+/* Update confdb Service */
+#define CONFDB_UPDATE_CONF_ENTRY "config/updateconfdb"
 
 struct confdb_ctx;
 struct config_file_ctx;
diff --git a/src/responder/update_confdb/update_confdb.c b/src/responder/update_confdb/update_confdb.c
new file mode 100644
index 0000000..aae5f5b
--- /dev/null
+++ b/src/responder/update_confdb/update_confdb.c
@@ -0,0 +1,309 @@
+/*
+    Authors:
+        Fabiano Fidêncio <fiden...@redhat.com>
+
+    Copyright (C) 2016 Red Hat
+
+    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
+    the Free Software Foundation; either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <popt.h>
+
+#include "util/util.h"
+#include "confdb/confdb_setup.h"
+#include "responder/common/responder.h"
+
+
+/* Dummy, not used here but required to link to other responder files */
+struct cli_protocol_version *register_cli_protocol_version(void)
+{
+    return NULL;
+}
+
+static errno_t update_confdb_update(struct cli_ctx *cctx)
+{
+    TALLOC_CTX *tmp_ctx;
+    struct confdb_ctx *confdb;
+    char *path;
+    errno_t ret;
+
+    tmp_ctx = talloc_new(NULL);
+    if (tmp_ctx == NULL) {
+        return ENOMEM;
+    }
+
+    path = talloc_asprintf(tmp_ctx, "%s/%s", DB_PATH, CONFDB_FILE);
+    if (path == NULL) {
+        return ENOMEM;
+    }
+
+    ret = confdb_setup(tmp_ctx, path, SSSD_CONFIG_FILE, CONFDB_DEFAULT_CONFIG_DIR, &confdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Unable to setup ConfDB [%d]: %s\n",
+              ret, strerror(ret));
+        goto done;
+    }
+
+    ret = EOK;
+
+    TEVENT_FD_WRITEABLE(cctx->cfde);
+
+done:
+    talloc_free(tmp_ctx);
+    return ret;
+}
+
+static int update_confdb_send_data(int fd)
+{
+    char data = '1';
+    ssize_t len;
+
+    errno = 0;
+    len = send(fd, &data, 1, 0);
+    if (len == -1) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            return EAGAIN;
+        } else {
+            return errno;
+        }
+    }
+
+    if (len == 0) {
+        return EIO;
+    }
+
+    return EOK;
+}
+
+static void update_confdb_send(struct cli_ctx *cctx)
+{
+    int ret;
+
+    ret = update_confdb_send_data(cctx->cfd);
+    if (ret == EAGAIN) {
+        /* not all data was sent, loop again */
+        return;
+    }
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
+        talloc_free(cctx);
+
+        return;
+    }
+
+    /* ok all sent */
+    TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
+    TEVENT_FD_READABLE(cctx->cfde);
+
+    exit(0);
+}
+
+static int update_confdb_recv_data(int fd)
+{
+    char data;
+    ssize_t len;
+
+    errno = 0;
+    len = recv(fd, &data, 1, 0);
+    if (len == -1) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            return EAGAIN;
+        } else {
+            return errno;
+        }
+    }
+
+    if (len == 0) {
+        return ENODATA;
+    }
+
+    return EOK;
+}
+
+static void update_confdb_recv(struct cli_ctx *cctx)
+{
+    int ret;
+
+    ret = update_confdb_recv_data(cctx->cfd);
+    switch(ret) {
+    case ENODATA:
+        DEBUG(SSSDBG_TRACE_ALL,
+              "Client closed connection\n");
+        talloc_free(cctx);
+        return;
+    case EAGAIN:
+        DEBUG(SSSDBG_TRACE_ALL,
+              "Interrupted before any data could be read, retry later\n");
+        return;
+    case EOK:
+        /* all fine */
+        break;
+    default:
+        DEBUG(SSSDBG_FATAL_FAILURE,
+              "Failed to receive data (%d, %s), aborting client!\n",
+              ret, strerror(ret));
+        talloc_free(cctx);
+        return;
+    }
+
+    TEVENT_FD_NOT_READABLE(cctx->cfde);
+    update_confdb_update(cctx);
+
+    return;
+}
+
+static void update_confdb_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(SSSDBG_CRIT_FAILURE,
+              "Could not create idle timer for client. "
+              "This connection may not auto-terminate\n");
+        /* Non-fatal, continue */
+    }
+
+    if (flags & TEVENT_FD_READ) {
+        update_confdb_recv(cctx);
+        return;
+    }
+
+    if (flags & TEVENT_FD_WRITE) {
+        update_confdb_send(cctx);
+        return;
+    }
+}
+
+static int update_confdb_connection_setup(struct cli_ctx *cctx)
+{
+    cctx->cfd_handler = update_confdb_fd_handler;
+
+    return EOK;
+}
+
+static int update_confdb_ctx_destructor(void *ptr)
+{
+    struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
+
+    /* mark that we are shutting down the service, so it is propagated
+     * into underlying contexts that are freed right before rctx */
+    DEBUG(SSSDBG_TRACE_FUNC, "Service is being shutdown\n");
+    rctx->shutting_down = true;
+
+    return 0;
+}
+
+static int update_confdb_process_init(TALLOC_CTX *mem_ctx,
+                                      struct tevent_context *ev,
+                                      struct confdb_ctx *cdb)
+{
+    struct resp_ctx *rctx;
+    int ret;
+
+    rctx = talloc_zero(mem_ctx, struct resp_ctx);
+    if (rctx == NULL) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n");
+
+        return ENOMEM;
+    }
+
+    rctx->ev = ev;
+    rctx->cdb = cdb;
+    rctx->sock_name = SSS_UPDATE_CONFDB_SOCKET_NAME;
+    rctx->shutting_down = false;
+    rctx->client_idle_timeout = CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT;
+
+    talloc_set_destructor((TALLOC_CTX *)rctx, update_confdb_ctx_destructor);
+
+    ret = activate_unix_sockets(rctx, update_confdb_connection_setup);
+    if (ret != EOK) {
+        goto fail;
+    }
+
+    DEBUG(SSSDBG_TRACE_FUNC, "Update ConfDB socket activation complete\n");
+
+    return EOK;
+
+fail:
+    talloc_free(rctx);
+    return ret;
+}
+
+int main (int argc, const char *argv[])
+{
+    int opt;
+    poptContext pc;
+    struct main_context *main_ctx;
+    int ret;
+
+    struct poptOption long_options[] = {
+        POPT_AUTOHELP
+        SSSD_MAIN_OPTS
+        POPT_TABLEEND
+    };
+
+    /* Set debug level to invalid value so we can decide if -d 0 was used. */
+    debug_level = SSSDBG_INVALID;
+
+    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
+    while((opt = poptGetNextOpt(pc)) != -1) {
+        switch(opt) {
+        default:
+            fprintf(stderr, "\nInvalid option %s: %s\n\n",
+                    poptBadOption(pc, 0), poptStrerror(opt));
+            poptPrintUsage(pc, stderr, 0);
+            return 1;
+        }
+    }
+
+    poptFreeContext(pc);
+
+    debug_level = SSSDBG_TRACE_ALL;
+
+    DEBUG_INIT(debug_level);
+
+    /* set up things like debug, signals, daemonizations, etc ... */
+    debug_log_file = "sssd_update_confdb";
+
+    ret = server_setup("update_confdb", 0, 0, 0,
+                       CONFDB_UPDATE_CONF_ENTRY, &main_ctx);
+    if (ret != EOK) {
+        return 2;
+    }
+
+    ret = die_if_parent_died();
+    if (ret != EOK) {
+        /* This is not fatal, don't return. */
+        DEBUG(SSSDBG_OP_FAILURE,
+              "Could not set up to exit when parent process does\n");
+    }
+
+    ret = update_confdb_process_init(main_ctx,
+                                     main_ctx->event_ctx,
+                                     main_ctx->confdb_ctx);
+    if (ret != EOK) {
+        return 3;
+    }
+
+    /* loop on main */
+    server_loop(main_ctx);
+
+    return 0;
+}
diff --git a/src/sysv/systemd/sssd-update-confdb.service.in b/src/sysv/systemd/sssd-update-confdb.service.in
new file mode 100644
index 0000000..7ae0852
--- /dev/null
+++ b/src/sysv/systemd/sssd-update-confdb.service.in
@@ -0,0 +1,8 @@
+[Unit]
+Description=SSSD Update ConfDB Service
+
+[Install]
+Also=sssd-update-confdb.socket
+
+[Service]
+ExecStart=@libexecdir@/sssd/sssd_update_confdb --debug-to-files
diff --git a/src/sysv/systemd/sssd-update-confdb.socket.in b/src/sysv/systemd/sssd-update-confdb.socket.in
new file mode 100644
index 0000000..7802e1d
--- /dev/null
+++ b/src/sysv/systemd/sssd-update-confdb.socket.in
@@ -0,0 +1,8 @@
+[Unit]
+Description=SSSD Update ConfDB socket
+
+[Socket]
+ListenStream=@localstatedir@/run/update-confdb.socket
+
+[Install]
+WantedBy=sockets.target

From 2b5594c5e1fad1745306edb9ee9ef99b4d2f08bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com>
Date: Mon, 19 Sep 2016 12:03:46 +0200
Subject: [PATCH 2/3] UTIL: Make set_fd_common_opts() friendly to Unix sockets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

TCP_NODELAY is not supported when dealing with AF_UNIX family.

Related:
https://fedorahosted.org/sssd/ticket/#3138

Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com>
---
 src/util/sss_sockets.c | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/src/util/sss_sockets.c b/src/util/sss_sockets.c
index 5e9be9e..1daebbf 100644
--- a/src/util/sss_sockets.c
+++ b/src/util/sss_sockets.c
@@ -74,7 +74,7 @@ static errno_t set_fcntl_flags(int fd, int fd_flags, int fl_flags)
     return EOK;
 }
 
-static errno_t set_fd_common_opts(int fd)
+static errno_t set_fd_common_opts(int fd, sa_family_t sa_family)
 {
     int dummy = 1;
     int ret;
@@ -89,12 +89,14 @@ static errno_t set_fd_common_opts(int fd)
                   strerror(ret));
     }
 
-    ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
-    if (ret != 0) {
-        ret = errno;
-        DEBUG(SSSDBG_FUNC_DATA,
-              "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
+    if (sa_family != AF_UNIX) {
+        ret = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &dummy, sizeof(dummy));
+        if (ret != 0) {
+            ret = errno;
+            DEBUG(SSSDBG_FUNC_DATA,
+                  "setsockopt TCP_NODELAY failed.[%d][%s].\n", ret,
                   strerror(ret));
+        }
     }
 
     return EOK;
@@ -264,7 +266,7 @@ struct tevent_req *sssd_async_socket_init_send(TALLOC_CTX *mem_ctx,
         goto fail;
     }
 
-    ret = set_fd_common_opts(state->sd);
+    ret = set_fd_common_opts(state->sd, addr->ss_family);
     if (ret != EOK) {
         DEBUG(SSSDBG_CRIT_FAILURE, "set_fd_common_opts failed.\n");
         goto fail;

From 8297f824f4da8fe983138ce1082ed07005a26a16 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com>
Date: Mon, 19 Sep 2016 20:01:36 +0200
Subject: [PATCH 3/3] SECRETS: Update confdb when starting the process
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

In order to get up-to-date configurations let's update the confdb file
when initializing secrets service.

It's done by socket-activating sssd-update-confdb process, which is
implemented now as:
- sends a single byte to the sssd-update-confdb socket, which will
  trigger the service
- waits till one byte comes back
- initialize secrets service as it was done before

Related:
https://fedorahosted.org/sssd/ticket/3138

Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com>
---
 src/responder/secrets/secsrv.c | 282 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 279 insertions(+), 3 deletions(-)

diff --git a/src/responder/secrets/secsrv.c b/src/responder/secrets/secsrv.c
index eb194a1..9ddb1d9 100644
--- a/src/responder/secrets/secsrv.c
+++ b/src/responder/secrets/secsrv.c
@@ -28,8 +28,19 @@
 #include "responder/secrets/secsrv.h"
 #include "resolv/async_resolv.h"
 
+#include "util/sss_sockets.h"
+
 #define DEFAULT_SEC_FD_LIMIT 2048
 
+struct sec_update_confdb_state {
+    struct TALLOC_CTX *mem_ctx;
+    struct tevent_context *ev;
+    struct confdb_ctx *cdb;
+
+    int sd;
+    struct tevent_fd *fde;
+};
+
 static int sec_get_config(struct sec_ctx *sctx)
 {
     int ret;
@@ -137,6 +148,271 @@ static int sec_process_init(TALLOC_CTX *mem_ctx,
     return ret;
 }
 
+static int sec_update_confdb_state_destructor(void *data)
+{
+    struct sec_update_confdb_state *state;
+
+    state = talloc_get_type(data, struct sec_update_confdb_state);
+
+    if (!state) return 0 ;
+
+    if (state->sd != -1) {
+        DEBUG(SSSDBG_TRACE_FUNC, "closing socket [%d]\n", state->sd);
+        close(state->sd);
+        state->sd = -1;
+    }
+
+    state->mem_ctx = NULL;
+    state->ev = NULL;
+    state->cdb = NULL;
+
+    return 0;
+}
+
+static int sec_update_confdb_fd_send_data(int fd)
+{
+    char data = '1';
+    ssize_t len;
+
+    errno = 0;
+    len = send(fd, &data, 1, 0);
+    if (len == -1) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            return EAGAIN;
+        } else {
+            return errno;
+        }
+    }
+
+    if (len == 0) {
+        return EIO;
+    }
+
+    return EOK;
+}
+
+static void sec_update_confdb_fd_send(void *data)
+{
+    struct tevent_req *req;
+    struct sec_update_confdb_state *state;
+    int ret;
+
+    req = talloc_get_type(data, struct tevent_req);
+    state = tevent_req_data(req, struct sec_update_confdb_state);
+
+    ret = sec_update_confdb_fd_send_data(state->sd);
+    if (ret == EAGAIN) {
+        /* not all data was sent, loop again */
+        return;
+    }
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
+
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* ok all sent */
+    TEVENT_FD_NOT_WRITEABLE(state->fde);
+    TEVENT_FD_READABLE(state->fde);
+}
+
+static int sec_update_confdb_fd_recv_data(int fd)
+{
+    char data;
+    ssize_t len;
+
+    errno = 0;
+    len = recv(fd, &data, 1, 0);
+    if (len == -1) {
+        if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) {
+            return EAGAIN;
+        } else {
+            return errno;
+        }
+    }
+
+    if (len == 0) {
+        return ENODATA;
+    }
+
+    return EOK;
+}
+
+static void sec_update_confdb_fd_recv(void *data)
+{
+    struct tevent_req *req;
+    struct sec_update_confdb_state *state;
+    int ret;
+
+    req = talloc_get_type(data, struct tevent_req);
+    state = tevent_req_data(req, struct sec_update_confdb_state);
+
+    ret = sec_update_confdb_fd_recv_data(state->sd);
+
+    switch(ret) {
+        case ENODATA:
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "Client closed connection\n");
+            tevent_req_error(req, EIO);
+            return;
+        case EAGAIN:
+            DEBUG(SSSDBG_TRACE_ALL,
+                  "Interrupted before any data could be read, retry later\n");
+            return;
+        case EOK:
+            /* all fine */
+            break;
+        default:
+            DEBUG(SSSDBG_FATAL_FAILURE,
+                  "Failed to receive data (%d, %s), aborting client\n",
+                  ret, strerror(ret));
+            tevent_req_error(req, ret);
+            return;
+    }
+
+
+    TEVENT_FD_NOT_READABLE(state->fde);
+
+    ret = sec_process_init(state->mem_ctx, state->ev, state->cdb);
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+                "sec_process_init failed: [%d]: %s.\n",
+                ret, strerror(ret));
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+static void sec_update_confdb_fd_handler(struct tevent_context *ev,
+                                         struct tevent_fd *fde,
+                                         uint16_t flags, void *data)
+{
+    if (flags & TEVENT_FD_READ) {
+        sec_update_confdb_fd_recv(data);
+        return;
+    }
+
+    if (flags & TEVENT_FD_WRITE) {
+        sec_update_confdb_fd_send(data);
+        return;
+    }
+}
+
+static void sec_update_confdb_connect_done(struct tevent_req *subreq)
+{
+    struct tevent_req *req;
+    struct sec_update_confdb_state *state;
+    int ret;
+
+    req = tevent_req_callback_data(subreq, struct tevent_req);
+    state = tevent_req_data(req, struct sec_update_confdb_state);
+
+    ret = sssd_async_socket_init_recv(subreq, &state->sd);
+    talloc_zfree(subreq);
+
+    if (ret != EOK) {
+        DEBUG(SSSDBG_CRIT_FAILURE,
+              "sssd_async_socket_init request failed: [%d]: %s.\n",
+              ret, strerror(ret));
+
+        tevent_req_error(req, ret);
+        return;
+    }
+
+    /* EOK */
+
+    state->fde = tevent_add_fd(state->ev, state, state->sd,
+                               TEVENT_FD_WRITE,
+                               sec_update_confdb_fd_handler, req);
+    if (!state->fde) {
+        tevent_req_error(req, EIO);
+        return;
+    }
+
+    tevent_req_done(req);
+}
+
+static struct tevent_req *
+sec_update_confdb_connect(TALLOC_CTX *mem_ctx,
+                          struct tevent_context *ev,
+                          struct confdb_ctx *cdb,
+                          struct sockaddr_storage *addr,
+                          int addr_len, int timeout)
+{
+    struct tevent_req *req, *subreq;
+    struct sec_update_confdb_state *state;
+
+    req = tevent_req_create(mem_ctx, &state, struct sec_update_confdb_state);
+    if (!req) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "tevent_req_create failed.\n");
+        return NULL;
+    }
+
+    talloc_set_destructor((TALLOC_CTX *)state, sec_update_confdb_state_destructor);
+
+    state->mem_ctx = mem_ctx;
+    state->ev = ev;
+    state->cdb = cdb;
+    state->sd = -1;
+
+    subreq = sssd_async_socket_init_send(state, ev, addr, addr_len, timeout);
+    if (!subreq) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "sssd_async_socket_init_send failed.\n");
+
+        tevent_req_error(req, ENOMEM);
+        tevent_req_post(req, ev);
+
+        goto end;
+    }
+
+    tevent_req_set_callback(subreq, sec_update_confdb_connect_done, req);
+
+end:
+    return req;
+}
+
+static int sec_update_confdb(TALLOC_CTX *mem_ctx,
+                             struct tevent_context *ev,
+                             struct confdb_ctx *cdb)
+{
+    struct tevent_req *req;
+    struct sockaddr_storage *sockaddr;
+
+    sockaddr = talloc_zero(mem_ctx, struct sockaddr_storage);
+    if (sockaddr == NULL) {
+        DEBUG(SSSDBG_CRIT_FAILURE, "talloc_zero failed.\n");
+        return ENOMEM;
+    }
+
+    /* Updating confdb will be done in a few steps:
+     *
+     * 1) Connect to the update-confdb.socket
+     * 2) Send a single byte to update-confdb.socket,
+     *    which will actually trigger the update.
+     * 3) Receive a single byte as a confirmation that
+     *    the update happened without issues
+     * 4) Finish the initialization using the up-to-date
+     *    values from the confdb.
+     */
+
+    ((struct sockaddr_un *)sockaddr)->sun_family = AF_UNIX;
+    memcpy(&((struct sockaddr_un *) sockaddr)->sun_path,
+           SSS_UPDATE_CONFDB_SOCKET_NAME,
+           strlen(SSS_UPDATE_CONFDB_SOCKET_NAME));
+
+    req = sec_update_confdb_connect(mem_ctx, ev, cdb, sockaddr,
+                                    SUN_LEN((struct sockaddr_un *) sockaddr),
+                                    CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT);
+
+    if (!req) return ENOMEM;
+
+    return EOK;
+}
+
 int main(int argc, const char *argv[])
 {
     int opt;
@@ -187,9 +463,9 @@ int main(int argc, const char *argv[])
               "Could not set up to exit when parent process does\n");
     }
 
-    ret = sec_process_init(main_ctx,
-                           main_ctx->event_ctx,
-                           main_ctx->confdb_ctx);
+    ret = sec_update_confdb(main_ctx,
+                            main_ctx->event_ctx,
+                            main_ctx->confdb_ctx);
     if (ret != EOK) return 3;
 
     /* loop on main */
_______________________________________________
sssd-devel mailing list -- sssd-devel@lists.fedorahosted.org
To unsubscribe send an email to sssd-devel-le...@lists.fedorahosted.org

Reply via email to