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

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 ef458b32b5c467cf851911e815148bbb21ea7406 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fabiano=20Fid=C3=AAncio?= <fiden...@redhat.com>
Date: Thu, 22 Sep 2016 18:02:30 +0200
Subject: [PATCH 1/4] SPEC: Don't restart sssd-secrets service on %postun
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

As sssd-secrets is a socket-activated service, just restarting the
sssd-secrets.socket is enough. The service will be re-started on demand
when needed.

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

Signed-off-by: Fabiano Fidêncio <fiden...@redhat.com>
---
 contrib/sssd.spec.in | 1 -
 1 file changed, 1 deletion(-)

diff --git a/contrib/sssd.spec.in b/contrib/sssd.spec.in
index 1f79ca7..ffae63e 100644
--- a/contrib/sssd.spec.in
+++ b/contrib/sssd.spec.in
@@ -1090,7 +1090,6 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us
 %postun common
 %systemd_postun_with_restart sssd.service
 %systemd_postun_with_restart sssd-secrets.socket
-%systemd_postun_with_restart sssd-secrets.service
 
 %else
 # sysv

From f7942475c7082f5dfcb4502302dea6d99a071bac 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 2/4] 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                           |   6 +
 src/confdb/confdb.h                            |   2 +
 src/responder/update_confdb/update_confdb.c    | 307 +++++++++++++++++++++++++
 src/sysv/systemd/sssd-update-confdb.service.in |   8 +
 src/sysv/systemd/sssd-update-confdb.socket.in  |   8 +
 6 files changed, 358 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 ffae63e..a37b9a4 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}
@@ -1081,14 +1084,17 @@ getent passwd sssd >/dev/null || useradd -r -g sssd -d / -s /sbin/nologin -c "Us
 # systemd
 %post common
 %systemd_post sssd.service
+%systemd_post sssd-update-confdb.socket
 %systemd_post sssd-secrets.socket
 
 %preun common
 %systemd_preun sssd.service
+%systemd_preun sssd-update-confdb.socket
 %systemd_preun sssd-secrets.socket
 
 %postun common
 %systemd_postun_with_restart sssd.service
+%systemd_postun_with_restart sssd-update-confdb.socket
 %systemd_postun_with_restart sssd-secrets.socket
 
 %else
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..f6617c0
--- /dev/null
+++ b/src/responder/update_confdb/update_confdb.c
@@ -0,0 +1,307 @@
+/*
+    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_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 7acfb1234f05109df7d3c8c1a123b215ac589d4d 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 3/4] 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 1b221a4513c53c3e05544b9351c229cce361b052 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 4/4] 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 ++++++++++++++++++++++++++++++++++++++++-
 src/tests/intg/test_secrets.py |  31 ++++-
 2 files changed, 305 insertions(+), 8 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 */
diff --git a/src/tests/intg/test_secrets.py b/src/tests/intg/test_secrets.py
index e394d12..4a5583e 100644
--- a/src/tests/intg/test_secrets.py
+++ b/src/tests/intg/test_secrets.py
@@ -43,11 +43,30 @@ def create_sssd_secrets_fixture(request):
     if subprocess.call(['sssd', "--genconf"]) != 0:
         raise Exception("failed to regenerate confdb")
 
-    resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_secrets")
+    # Starting the process manually and waiting till the socket is
+    # created is something that has to be done as we cannot rely on
+    # systemd's socket-activation for the integration tests.
+    update_confdb_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_update_confdb")
+    update_confdb_pid = os.fork()
+    if update_confdb_pid == 0:
+        if subprocess.call(update_confdb_path) != 0:
+            raise Exception("sssd_secrets failed to start")
 
+    sock_path = os.path.join(config.RUNSTATEDIR, "update-confdb.socket")
+    sck = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+    for _ in range(1, 10):
+        try:
+            sck.connect(udpdate_cdb_path)
+        except:
+            time.sleep(0.1)
+        else:
+            break
+    sck.close()
+
+    resp_path = os.path.join(config.LIBEXEC_PATH, "sssd", "sssd_secrets")
     secpid = os.fork()
     if secpid == 0:
-        if subprocess.call([resp_path, "--uid=0", "--gid=0"]) != 0:
+        if subprocess.call([resp_path, "--uid=0", "--gid=0", "--debug-level=9"]) != 0:
             raise Exception("sssd_secrets failed to start")
 
     sock_path = os.path.join(config.RUNSTATEDIR, "secrets.socket")
@@ -62,10 +81,12 @@ def create_sssd_secrets_fixture(request):
     sck.close()
 
     def sec_teardown():
-        if secpid == 0:
-            return
+        if secpid != 0:
+            os.kill(secpid, signal.SIGTERM)
+
+        if update_confdb_pid != 0:
+            os.kill(update_confdb_pid, signal.SIGTERM)
 
-        os.kill(secpid, signal.SIGTERM)
         for secdb_file in os.listdir(config.SECDB_PATH):
             os.unlink(config.SECDB_PATH + "/" + secdb_file)
     request.addfinalizer(sec_teardown)
_______________________________________________
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