From b67dbadc979cbe86545e2275223483d429b74747 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Mon, 23 Nov 2009 14:33:55 -0500 Subject: 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 (limited to 'server') diff --git a/server/Makefile.am b/server/Makefile.am index c0293913..69e5fd38 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 \ @@ -555,6 +556,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 \ @@ -590,6 +592,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 \ @@ -605,6 +608,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 \ @@ -643,6 +647,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) \ @@ -650,6 +655,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 00000000..9ec09f29 --- /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 + + 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 . +*/ + +#include +#include +#include +#include + +#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 00000000..75cb3a6f --- /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 + + 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 . +*/ + +#ifndef __CHILD_COMMON_H__ +#define __CHILD_COMMON_H__ + +#include +#include +#include + +#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 a3f381e4..a187d159 100644 --- a/server/providers/ipa/ipa_init.c +++ b/server/providers/ipa/ipa_init.c @@ -27,6 +27,7 @@ #include #include +#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 7ac440f0..3a5b27a7 100644 --- a/server/providers/krb5/krb5_auth.c +++ b/server/providers/krb5/krb5_auth.c @@ -27,7 +27,6 @@ #include #include -#include #include #include @@ -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 7facb003..f222c7b8 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 f7809d2c..c0e9fbf2 100644 --- a/server/providers/krb5/krb5_child.c +++ b/server/providers/krb5/krb5_child.c @@ -30,12 +30,11 @@ #include #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 a070c8c3..43cbc1bc 100644 --- a/server/providers/krb5/krb5_init.c +++ b/server/providers/krb5/krb5_init.c @@ -26,6 +26,7 @@ #include #include #include +#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; -- cgit