Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dyndns: collect nsupdate debug output #7713

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -2890,7 +2890,8 @@ dyndns_tests_SOURCES = \
$(SSSD_RESOLV_OBJ) \
src/tests/cmocka/common_mock_be.c \
src/tests/cmocka/test_dyndns.c \
src/providers/data_provider_opts.c
src/providers/data_provider_opts.c \
src/util/child_common.c
dyndns_tests_CFLAGS = \
$(AM_CFLAGS) \
$(CMOCKA_CFLAGS) \
Expand Down
150 changes: 100 additions & 50 deletions src/providers/be_dyndns.c
Original file line number Diff line number Diff line change
Expand Up @@ -793,9 +793,14 @@ nsupdate_get_addrs_recv(struct tevent_req *req,
* a timeout or when the child finishes operation.
*/
struct nsupdate_child_state {
struct tevent_context *ev;
int pipefd_to_child;
int pipefd_from_child;
struct tevent_timer *timeout_handler;
struct sss_child_ctx_old *child_ctx;
bool read_done;
bool process_finished;
errno_t result;

int child_status;
};
Expand All @@ -810,11 +815,13 @@ nsupdate_child_handler(int child_status,
void *pvt);

static void nsupdate_child_stdin_done(struct tevent_req *subreq);
void nsupdate_child_read_done(struct tevent_req *subreq);

static struct tevent_req *
nsupdate_child_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
int pipefd_to_child,
int pipefd_from_child,
pid_t child_pid,
char *child_stdin)
{
Expand All @@ -829,7 +836,13 @@ nsupdate_child_send(TALLOC_CTX *mem_ctx,
close(pipefd_to_child);
return NULL;
}

state->ev = ev;
state->pipefd_to_child = pipefd_to_child;
state->pipefd_from_child = pipefd_from_child;
state->read_done = false;
state->process_finished = false;
state->result = ERR_DYNDNS_FAILED;

/* Set up SIGCHLD handler */
ret = child_handler_setup(ev, child_pid, nsupdate_child_handler, req,
Expand Down Expand Up @@ -903,15 +916,65 @@ nsupdate_child_stdin_done(struct tevent_req *subreq)

ret = write_pipe_recv(subreq);
talloc_zfree(subreq);
PIPE_FD_CLOSE(state->pipefd_to_child);

if (ret != EOK) {
DEBUG(SSSDBG_OP_FAILURE, "Sending nsupdate data failed [%d]: %s\n",
ret, sss_strerror(ret));
tevent_req_error(req, ERR_DYNDNS_FAILED);
return;
}

PIPE_FD_CLOSE(state->pipefd_to_child);
subreq = read_pipe_send(state, state->ev, state->pipefd_from_child);
if (subreq == NULL) {
DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
tevent_req_error(req, ERR_DYNDNS_FAILED);
return;
}
tevent_req_set_callback(subreq, nsupdate_child_read_done, req);

/* Now either wait for the timeout to fire or the child
* to finish
*/
}

void nsupdate_child_read_done(struct tevent_req *subreq)
{
errno_t ret;
uint8_t *buf = NULL;
ssize_t buf_len = 0;
struct tevent_req *req =
tevent_req_callback_data(subreq, struct tevent_req);
struct nsupdate_child_state *state =
tevent_req_data(req, struct nsupdate_child_state);

talloc_zfree(state->timeout_handler);

ret = read_pipe_recv(subreq, state, &buf, &buf_len);
talloc_zfree(subreq);
PIPE_FD_CLOSE(state->pipefd_from_child);
if (ret != EOK) {
tevent_req_error(req, ret);
return;
}

if (buf_len != 0) {
DEBUG(SSSDBG_TRACE_LIBS, "--- nsupdate output start---\n"
"%.*s\n"
"--- nsupdate output end---\n",
(int) buf_len, buf);
} else {
DEBUG(SSSDBG_TRACE_LIBS, "No output from nsupdate.\n");
}

state->read_done = true;
if (state->process_finished) {
if (state->result == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, state->result);
}
}
/* Now either wait for the timeout to fire or the child
* to finish
*/
Expand All @@ -927,23 +990,29 @@ nsupdate_child_handler(int child_status,
tevent_req_data(req, struct nsupdate_child_state);

state->child_status = child_status;
state->result = EOK;

if (WIFEXITED(child_status) && WEXITSTATUS(child_status) != 0) {
DEBUG(SSSDBG_OP_FAILURE,
"Dynamic DNS child failed with status [%d]\n", child_status);
tevent_req_error(req, ERR_DYNDNS_FAILED);
return;
state->result = ERR_DYNDNS_FAILED;
}

if (WIFSIGNALED(child_status)) {
DEBUG(SSSDBG_OP_FAILURE,
"Dynamic DNS child was terminated by signal [%d]\n",
WTERMSIG(child_status));
tevent_req_error(req, ERR_DYNDNS_FAILED);
return;
state->result = ERR_DYNDNS_FAILED;
}

tevent_req_done(req);
state->process_finished = true;
if (state->read_done) {
if (state->result == EOK) {
tevent_req_done(req);
} else {
tevent_req_error(req, state->result);
}
}
}

static errno_t
Expand All @@ -969,9 +1038,9 @@ struct be_nsupdate_state {
};

static void be_nsupdate_done(struct tevent_req *subreq);
static char **be_nsupdate_args(TALLOC_CTX *mem_ctx,
enum be_nsupdate_auth auth_type,
bool force_tcp);
static const char **be_nsupdate_args(TALLOC_CTX *mem_ctx,
enum be_nsupdate_auth auth_type,
bool force_tcp);

struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
Expand All @@ -980,13 +1049,13 @@ struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
bool force_tcp)
{
int pipefd_to_child[2] = PIPE_INIT;
int pipefd_from_child[2] = PIPE_INIT;
pid_t child_pid;
errno_t ret;
struct tevent_req *req = NULL;
struct tevent_req *subreq = NULL;
struct be_nsupdate_state *state;
char **args;
int debug_fd;
const char **args;

req = tevent_req_create(mem_ctx, &state, struct be_nsupdate_state);
if (req == NULL) {
Expand All @@ -1001,49 +1070,36 @@ struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
"pipe failed [%d][%s].\n", ret, strerror(ret));
goto done;
}
ret = pipe(pipefd_from_child);
if (ret == -1) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"pipe (from) failed [%d][%s].\n", ret, strerror(ret));
goto done;
}

args = be_nsupdate_args(state, auth_type, force_tcp);
if (args == NULL) {
ret = ENOMEM;
goto done;
}

child_pid = fork();

if (child_pid == 0) { /* child */
PIPE_FD_CLOSE(pipefd_to_child[1]);
ret = dup2(pipefd_to_child[0], STDIN_FILENO);
if (ret == -1) {
ret = errno;
DEBUG(SSSDBG_CRIT_FAILURE,
"dup2 failed [%d][%s].\n", ret, strerror(ret));
goto done;
}

if (debug_level >= SSSDBG_TRACE_LIBS) {
debug_fd = get_fd_from_debug_file();
ret = dup2(debug_fd, STDERR_FILENO);
if (ret == -1) {
ret = errno;
DEBUG(SSSDBG_MINOR_FAILURE,
"dup2 failed [%d][%s].\n", ret, strerror(ret));
/* stderr is not fatal */
}
}

args = be_nsupdate_args(state, auth_type, force_tcp);
if (args == NULL) {
ret = ENOMEM;
goto done;
}

errno = 0;
execv(NSUPDATE_PATH, args);
/* The child should never end up here */
ret = errno;
exec_child_ex(state, pipefd_to_child, pipefd_from_child, NSUPDATE_PATH,
NULL, args, true, STDIN_FILENO, STDERR_FILENO);
DEBUG(SSSDBG_CRIT_FAILURE, "execv failed [%d][%s].\n", ret, strerror(ret));
goto done;
} else if (child_pid > 0) { /* parent */
PIPE_FD_CLOSE(pipefd_to_child[0]);
PIPE_FD_CLOSE(pipefd_from_child[1]);

/* the nsupdate_child request now owns the pipefd and is responsible
* for closing it
*/
subreq = nsupdate_child_send(state, ev, pipefd_to_child[1],
pipefd_from_child[0],
child_pid, nsupdate_msg);
if (subreq == NULL) {
ret = ERR_DYNDNS_FAILED;
Expand All @@ -1067,25 +1123,19 @@ struct tevent_req *be_nsupdate_send(TALLOC_CTX *mem_ctx,
return req;
}

static char **
static const char **
be_nsupdate_args(TALLOC_CTX *mem_ctx,
enum be_nsupdate_auth auth_type,
bool force_tcp)
{
char **argv;
const char **argv;
int argc = 0;

argv = talloc_zero_array(mem_ctx, char *, 6);
argv = talloc_zero_array(mem_ctx, const char *, 6);
if (argv == NULL) {
return NULL;
}

argv[argc] = talloc_strdup(argv, NSUPDATE_PATH);
if (argv[argc] == NULL) {
goto fail;
}
argc++;

switch (auth_type) {
case BE_NSUPDATE_AUTH_NONE:
DEBUG(SSSDBG_FUNC_DATA, "nsupdate auth type: none\n");
Expand Down
Loading