>From 3e56d347882ad9b6d7f78a3b9dfd97bf6c2a628e Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhrozek@redhat.com>
Date: Mon, 23 Nov 2009 14:33:55 -0500
Subject: [PATCH 1/2] Split helpers for child processes

Moves several functions out of providers/krb5 hierarchy into a separate
module so it can be shared by the ldap child.
---
 server/Makefile.am                 |    6 +
 server/providers/child_common.c    |  195 ++++++++++++++++++++++++++++++++++++
 server/providers/child_common.h    |   60 +++++++++++
 server/providers/ipa/ipa_init.c    |    3 +-
 server/providers/krb5/krb5_auth.c  |  144 +--------------------------
 server/providers/krb5/krb5_auth.h  |    5 -
 server/providers/krb5/krb5_child.c |   25 +-----
 server/providers/krb5/krb5_init.c  |    3 +-
 8 files changed, 267 insertions(+), 174 deletions(-)
 create mode 100644 server/providers/child_common.c
 create mode 100644 server/providers/child_common.h

diff --git a/server/Makefile.am b/server/Makefile.am
index c52db19..b80cdfd 100644
--- a/server/Makefile.am
+++ b/server/Makefile.am
@@ -291,6 +291,7 @@ dist_noinst_HEADERS = \
     providers/dp_backend.h \
     providers/fail_over.h \
     providers/providers.h \
+    providers/child_common.h \
     providers/krb5/krb5_auth.h \
     providers/krb5/krb5_common.h \
     providers/krb5/krb5_utils.h \
@@ -554,6 +555,7 @@ stress_tests_LDADD = \
 # Plugin Libraries #
 ####################
 libsss_ldap_la_SOURCES = \
+    providers/child_common.c \
     providers/ldap/ldap_id.c \
     providers/ldap/ldap_id_enum.c \
     providers/ldap/ldap_id_cleanup.c \
@@ -589,6 +591,7 @@ libsss_proxy_la_LDFLAGS = \
 
 libsss_krb5_la_SOURCES = \
     util/find_uid.c \
+    providers/child_common.c \
     providers/krb5/krb5_utils.c \
     providers/krb5/krb5_become_user.c \
     providers/krb5/krb5_auth.c \
@@ -604,6 +607,7 @@ libsss_krb5_la_LDFLAGS = \
     -module
 
 libsss_ipa_la_SOURCES = \
+    providers/child_common.c \
     providers/ipa/ipa_init.c \
     providers/ipa/ipa_common.c \
     providers/ipa/ipa_auth.c \
@@ -642,6 +646,7 @@ krb5_child_SOURCES = \
     $(SSSD_DEBUG_OBJ) \
     providers/krb5/krb5_become_user.c \
     providers/krb5/krb5_child.c \
+    providers/child_common.c \
     util/sss_krb5.c
 krb5_child_CFLAGS = \
     $(AM_CFLAGS) \
@@ -649,6 +654,7 @@ krb5_child_CFLAGS = \
     $(KRB5_CFLAGS)
 krb5_child_LDADD = \
     $(TALLOC_LIBS) \
+    $(TEVENT_LIBS) \
     $(POPT_LIBS) \
     $(KRB5_LIBS)
 
diff --git a/server/providers/child_common.c b/server/providers/child_common.c
new file mode 100644
index 0000000..9ec09f2
--- /dev/null
+++ b/server/providers/child_common.c
@@ -0,0 +1,195 @@
+/*
+    SSSD
+
+    Common helper functions to be used in child processes
+
+    Authors:
+        Sumit Bose   <sbose@redhat.com>
+
+    Copyright (C) 2009 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 <sys/types.h>
+#include <fcntl.h>
+#include <tevent.h>
+#include <sys/wait.h>
+
+#include "util/util.h"
+#include "util/find_uid.h"
+#include "db/sysdb.h"
+#include "providers/child_common.h"
+
+uint8_t *copy_buffer_and_add_zero(TALLOC_CTX *mem_ctx,
+                                  const uint8_t *src, size_t len)
+{
+    uint8_t *str;
+
+    str = talloc_size(mem_ctx, len + 1);
+    if (str == NULL) {
+        DEBUG(1, ("talloc_size failed.\n"));
+        return NULL;
+    }
+    memcpy(str, src, len);
+    str[len] = '\0';
+
+    return str;
+}
+
+/* Async communication with the child process via a pipe */
+
+struct read_pipe_state {
+    int fd;
+    uint8_t *buf;
+    size_t len;
+};
+
+static void read_pipe_done(struct tevent_context *ev,
+                           struct tevent_fd *fde,
+                           uint16_t flags, void *pvt);
+
+struct tevent_req *read_pipe_send(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev, int fd)
+{
+    struct tevent_req *req;
+    struct read_pipe_state *state;
+    struct tevent_fd *fde;
+
+    req = tevent_req_create(mem_ctx, &state, struct read_pipe_state);
+    if (req == NULL) return NULL;
+
+    state->fd = fd;
+    state->buf = talloc_array(state, uint8_t, MAX_CHILD_MSG_SIZE);
+    state->len = 0;
+    if (state->buf == NULL) goto fail;
+
+    fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
+                        read_pipe_done, req);
+    if (fde == NULL) {
+        DEBUG(1, ("tevent_add_fd failed.\n"));
+        goto fail;
+    }
+
+    return req;
+
+fail:
+    talloc_zfree(req);
+    return NULL;
+}
+
+static void read_pipe_done(struct tevent_context *ev,
+                           struct tevent_fd *fde,
+                           uint16_t flags, void *pvt)
+{
+    ssize_t size;
+    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
+    struct read_pipe_state *state = tevent_req_data(req, struct read_pipe_state);
+
+    if (flags & TEVENT_FD_WRITE) {
+        DEBUG(1, ("read_pipe_done called with TEVENT_FD_WRITE, this should not happen.\n"));
+        tevent_req_error(req, EINVAL);
+        return;
+    }
+
+    size = read(state->fd, state->buf + state->len, talloc_get_size(state->buf) - state->len);
+    if (size == -1) {
+        if (errno == EAGAIN || errno == EINTR) return;
+        DEBUG(1, ("read failed [%d][%s].\n", errno, strerror(errno)));
+        tevent_req_error(req, errno);
+        return;
+    } else if (size > 0) {
+        state->len += size;
+        if (state->len > talloc_get_size(state->buf)) {
+            DEBUG(1, ("read to much, this should never happen.\n"));
+            tevent_req_error(req, EINVAL);
+            return;
+        }
+        return;
+    } else if (size == 0) {
+        tevent_req_done(req);
+        return;
+    } else {
+        DEBUG(1, ("unexpected return value of read [%d].\n", size));
+        tevent_req_error(req, EINVAL);
+        return;
+    }
+}
+
+int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                   uint8_t **buf, ssize_t *len)
+{
+    struct read_pipe_state *state = tevent_req_data(req,
+                                                    struct read_pipe_state);
+
+    TEVENT_REQ_RETURN_ON_ERROR(req);
+
+    *buf = talloc_move(mem_ctx, &state->buf);
+    *len = state->len;
+
+    return EOK;
+}
+
+/* The pipes to communicate with the child must be nonblocking */
+void fd_nonblocking(int fd)
+{
+    int flags;
+    int ret;
+
+    flags = fcntl(fd, F_GETFL, 0);
+    if (flags == -1) {
+        ret = errno;
+        DEBUG(1, ("F_GETFL failed [%d][%s].\n", ret, strerror(ret)));
+        return;
+    }
+
+    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
+        ret = errno;
+        DEBUG(1, ("F_SETFL failed [%d][%s].\n", ret, strerror(ret)));
+    }
+
+    return;
+}
+
+void child_sig_handler(struct tevent_context *ev,
+                       struct tevent_signal *sige, int signum,
+                       int count, void *__siginfo, void *pvt)
+{
+    int ret;
+    int child_status;
+
+    DEBUG(7, ("Waiting for [%d] childeren.\n", count));
+    do {
+        errno = 0;
+        ret = waitpid(-1, &child_status, WNOHANG);
+
+        if (ret == -1) {
+            DEBUG(1, ("waitpid failed [%d][%s].\n", errno, strerror(errno)));
+        } else if (ret == 0) {
+            DEBUG(1, ("waitpid did not found a child with changed status.\n"));
+        } else  {
+            if (WEXITSTATUS(child_status) != 0) {
+                DEBUG(1, ("child [%d] failed with status [%d].\n", ret,
+                          child_status));
+            } else {
+                DEBUG(4, ("child [%d] finished successful.\n", ret));
+            }
+        }
+
+        --count;
+    } while (count < 0);
+
+    return;
+}
+
diff --git a/server/providers/child_common.h b/server/providers/child_common.h
new file mode 100644
index 0000000..75cb3a6
--- /dev/null
+++ b/server/providers/child_common.h
@@ -0,0 +1,60 @@
+/*
+    SSSD
+
+    Common helper functions to be used in child processes
+
+    Authors:
+        Sumit Bose   <sbose@redhat.com>
+
+    Copyright (C) 2009 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/>.
+*/
+
+#ifndef __CHILD_COMMON_H__
+#define __CHILD_COMMON_H__
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <tevent.h>
+
+#define IN_BUF_SIZE         512
+#define MAX_CHILD_MSG_SIZE  255
+
+struct response {
+    size_t max_size;
+    size_t size;
+    uint8_t *buf;
+};
+
+uint8_t *copy_buffer_and_add_zero(TALLOC_CTX *mem_ctx,
+                                  const uint8_t *src, size_t len);
+
+/* Async communication with the child process via a pipe */
+struct read_pipe_state;
+
+struct tevent_req *read_pipe_send(TALLOC_CTX *mem_ctx,
+                                  struct tevent_context *ev, int fd);
+
+int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
+                   uint8_t **buf, ssize_t *len);
+
+/* The pipes to communicate with the child must be nonblocking */
+void fd_nonblocking(int fd);
+
+void child_sig_handler(struct tevent_context *ev,
+                       struct tevent_signal *sige, int signum,
+                       int count, void *__siginfo, void *pvt);
+
+#endif /* __CHILD_COMMON_H__ */
diff --git a/server/providers/ipa/ipa_init.c b/server/providers/ipa/ipa_init.c
index a3f381e..a187d15 100644
--- a/server/providers/ipa/ipa_init.c
+++ b/server/providers/ipa/ipa_init.c
@@ -27,6 +27,7 @@
 #include <sys/stat.h>
 #include <fcntl.h>
 
+#include "providers/child_common.h"
 #include "providers/ipa/ipa_common.h"
 #include "providers/krb5/krb5_auth.h"
 #include "providers/ipa/ipa_auth.h"
@@ -195,7 +196,7 @@ int sssm_ipa_auth_init(struct be_ctx *bectx,
     }
 
     sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO,
-                             krb5_child_sig_handler, NULL);
+                             child_sig_handler, NULL);
     if (sige == NULL) {
         DEBUG(1, ("tevent_add_signal failed.\n"));
         ret = ENOMEM;
diff --git a/server/providers/krb5/krb5_auth.c b/server/providers/krb5/krb5_auth.c
index 7ac440f..3a5b27a 100644
--- a/server/providers/krb5/krb5_auth.c
+++ b/server/providers/krb5/krb5_auth.c
@@ -27,7 +27,6 @@
 
 #include <sys/types.h>
 #include <sys/wait.h>
-#include <fcntl.h>
 #include <pwd.h>
 #include <sys/stat.h>
 
@@ -36,6 +35,7 @@
 #include "util/util.h"
 #include "util/find_uid.h"
 #include "db/sysdb.h"
+#include "providers/child_common.h"
 #include "providers/krb5/krb5_auth.h"
 #include "providers/krb5/krb5_utils.h"
 
@@ -412,23 +412,6 @@ static struct krb5_ctx *get_krb5_ctx(struct be_req *be_req)
     }
 }
 
-static void fd_nonblocking(int fd)
-{
-    int flags;
-
-    flags = fcntl(fd, F_GETFL, 0);
-    if (flags == -1) {
-        DEBUG(1, ("F_GETFL failed [%d][%s].\n", errno, strerror(errno)));
-        return;
-    }
-
-    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
-        DEBUG(1, ("F_SETFL failed [%d][%s].\n", errno, strerror(errno)));
-    }
-
-    return;
-}
-
 static void krb_reply(struct be_req *req, int dp_err, int result);
 
 static void krb5_child_timeout(struct tevent_context *ev,
@@ -545,37 +528,6 @@ failed:
     return err;
 }
 
-void krb5_child_sig_handler(struct tevent_context *ev,
-                            struct tevent_signal *sige, int signum,
-                            int count, void *__siginfo, void *pvt)
-{
-    int ret;
-    int child_status;
-
-    DEBUG(7, ("Waiting for [%d] childeren.\n", count));
-    do {
-        errno = 0;
-        ret = waitpid(-1, &child_status, WNOHANG);
-
-        if (ret == -1) {
-            DEBUG(1, ("waitpid failed [%d][%s].\n", errno, strerror(errno)));
-        } else if (ret == 0) {
-            DEBUG(1, ("waitpid did not found a child with changed status.\n"));
-        } else  {
-            if (WEXITSTATUS(child_status) != 0) {
-                DEBUG(1, ("child [%d] failed with status [%d].\n", ret,
-                          child_status));
-            } else {
-                DEBUG(4, ("child [%d] finished successful.\n", ret));
-            }
-        }
-
-        --count;
-    } while (count < 0);
-
-    return;
-}
-
 static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
                                   struct krb5child_req *kr,
                                   char ***_argv)
@@ -745,100 +697,6 @@ static errno_t fork_child(struct krb5child_req *kr)
     return EOK;
 }
 
-
-struct read_pipe_state {
-    int fd;
-    uint8_t *buf;
-    size_t len;
-};
-
-static void read_pipe_done(struct tevent_context *ev,
-                           struct tevent_fd *fde,
-                           uint16_t flags, void *pvt);
-
-static struct tevent_req *read_pipe_send(TALLOC_CTX *memctx,
-                                         struct tevent_context *ev, int fd)
-{
-    struct tevent_req *req;
-    struct read_pipe_state *state;
-    struct tevent_fd *fde;
-
-
-    req = tevent_req_create(memctx, &state, struct read_pipe_state);
-    if (req == NULL) return NULL;
-
-    state->fd = fd;
-    state->buf = talloc_array(state, uint8_t, MAX_CHILD_MSG_SIZE);
-    state->len = 0;
-    if (state->buf == NULL) goto fail;
-
-    fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
-                       read_pipe_done, req);
-    if (fde == NULL) {
-        DEBUG(1, ("tevent_add_fd failed.\n"));
-        goto fail;
-    }
-
-    return req;
-
-fail:
-    talloc_zfree(req);
-    return NULL;
-}
-
-static void read_pipe_done(struct tevent_context *ev,
-                           struct tevent_fd *fde,
-                           uint16_t flags, void *pvt)
-{
-    ssize_t size;
-    struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
-    struct read_pipe_state *state = tevent_req_data(req, struct read_pipe_state);
-
-    if (flags & TEVENT_FD_WRITE) {
-        DEBUG(1, ("read_pipe_done called with TEVENT_FD_WRITE, this should not happen.\n"));
-        tevent_req_error(req, EINVAL);
-        return;
-    }
-
-    size = read(state->fd, state->buf + state->len, talloc_get_size(state->buf) - state->len);
-    if (size == -1) {
-        if (errno == EAGAIN || errno == EINTR) return;
-        DEBUG(1, ("read failed [%d][%s].\n", errno, strerror(errno)));
-        tevent_req_error(req, errno);
-        return;
-    } else if (size > 0) {
-        state->len += size;
-        if (state->len > talloc_get_size(state->buf)) {
-            DEBUG(1, ("read to much, this should never happen.\n"));
-            tevent_req_error(req, EINVAL);
-            return;
-        }
-        return;
-    } else if (size == 0) {
-        tevent_req_done(req);
-        return;
-    } else {
-        DEBUG(1, ("unexpected return value of read [%d].\n", size));
-        tevent_req_error(req, EINVAL);
-        return;
-    }
-
-}
-
-static int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
-                          uint8_t **buf, ssize_t *len)
-{
-    struct read_pipe_state *state = tevent_req_data(req,
-                                                    struct read_pipe_state);
-
-    TEVENT_REQ_RETURN_ON_ERROR(req);
-
-    *buf = talloc_move(mem_ctx, &state->buf);
-    *len = state->len;
-
-    return EOK;
-}
-
 struct handle_child_state {
     struct krb5child_req *kr;
     ssize_t len;
diff --git a/server/providers/krb5/krb5_auth.h b/server/providers/krb5/krb5_auth.h
index 7facb00..f222c7b 100644
--- a/server/providers/krb5/krb5_auth.h
+++ b/server/providers/krb5/krb5_auth.h
@@ -30,7 +30,6 @@
 #include "providers/dp_backend.h"
 #include "providers/krb5/krb5_common.h"
 
-#define MAX_CHILD_MSG_SIZE 255
 #define CCACHE_ENV_NAME "KRB5CCNAME"
 #define SSSD_KRB5_CHANGEPW_PRINCIPLE "SSSD_KRB5_CHANGEPW_PRINCIPLE"
 
@@ -88,8 +87,4 @@ struct krb5_ctx {
 
 void krb5_pam_handler(struct be_req *be_req);
 
-void krb5_child_sig_handler(struct tevent_context *ev,
-                            struct tevent_signal *sige, int signum,
-                            int count, void *__siginfo, void *pvt);
-
 #endif /* __KRB5_AUTH_H__ */
diff --git a/server/providers/krb5/krb5_child.c b/server/providers/krb5/krb5_child.c
index f7809d2..c0e9fbf 100644
--- a/server/providers/krb5/krb5_child.c
+++ b/server/providers/krb5/krb5_child.c
@@ -30,12 +30,11 @@
 #include <security/pam_modules.h>
 
 #include "util/util.h"
+#include "providers/child_common.h"
 #include "providers/dp_backend.h"
 #include "providers/krb5/krb5_auth.h"
 #include "providers/krb5/krb5_utils.h"
 
-#define IN_BUF_SIZE 512
-
 struct krb5_child_ctx {
     /* opts taken from kinit */
     /* in seconds */
@@ -99,12 +98,6 @@ static const char *__krb5_error_msg;
     sss_krb5_free_error_message(krb5_error_ctx, __krb5_error_msg); \
 } while(0);
 
-struct response {
-    size_t max_size;
-    size_t size;
-    uint8_t *buf;
-};
-
 static krb5_error_code create_ccache_file(struct krb5_req *kr, krb5_creds *creds)
 {
     krb5_error_code kerr;
@@ -618,22 +611,6 @@ static errno_t create_empty_ccache(int fd, struct krb5_req *kr)
     return ret;
 }
 
-uint8_t *copy_buffer_and_add_zero(TALLOC_CTX *mem_ctx, const uint8_t *src,
-                                  size_t len)
-{
-    uint8_t *str;
-
-    str = talloc_size(mem_ctx, len + 1);
-    if (str == NULL) {
-        DEBUG(1, ("talloc_size failed.\n"));
-        return NULL;
-    }
-    memcpy(str, src, len);
-    str[len] = '\0';
-
-    return str;
-}
-
 static errno_t unpack_buffer(uint8_t *buf, size_t size, struct pam_data *pd,
                              char **ccname, char **keytab, uint32_t *validate)
 {
diff --git a/server/providers/krb5/krb5_init.c b/server/providers/krb5/krb5_init.c
index a070c8c..43cbc1b 100644
--- a/server/providers/krb5/krb5_init.c
+++ b/server/providers/krb5/krb5_init.c
@@ -26,6 +26,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include "providers/child_common.h"
 #include "providers/krb5/krb5_auth.h"
 #include "providers/krb5/krb5_common.h"
 
@@ -108,7 +109,7 @@ int sssm_krb5_auth_init(struct be_ctx *bectx,
     }
 
     sige = tevent_add_signal(bectx->ev, ctx, SIGCHLD, SA_SIGINFO,
-                             krb5_child_sig_handler, NULL);
+                             child_sig_handler, NULL);
     if (sige == NULL) {
         DEBUG(1, ("tevent_add_signal failed.\n"));
         ret = ENOMEM;
-- 
1.6.2.5

