LCOV - code coverage report
Current view: top level - util - child_common.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 177 344 51.5 %
Date: 2016-06-29 Functions: 16 20 80.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Common helper functions to be used in child processes
       5             : 
       6             :     Authors:
       7             :         Sumit Bose   <sbose@redhat.com>
       8             : 
       9             :     Copyright (C) 2009 Red Hat
      10             : 
      11             :     This program is free software; you can redistribute it and/or modify
      12             :     it under the terms of the GNU General Public License as published by
      13             :     the Free Software Foundation; either version 3 of the License, or
      14             :     (at your option) any later version.
      15             : 
      16             :     This program is distributed in the hope that it will be useful,
      17             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      18             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      19             :     GNU General Public License for more details.
      20             : 
      21             :     You should have received a copy of the GNU General Public License
      22             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      23             : */
      24             : 
      25             : #include <sys/types.h>
      26             : #include <fcntl.h>
      27             : #include <tevent.h>
      28             : #include <sys/wait.h>
      29             : #include <errno.h>
      30             : 
      31             : #include "util/util.h"
      32             : #include "util/find_uid.h"
      33             : #include "db/sysdb.h"
      34             : #include "util/child_common.h"
      35             : 
      36             : struct sss_sigchild_ctx {
      37             :     struct tevent_context *ev;
      38             :     hash_table_t *children;
      39             :     int options;
      40             : };
      41             : 
      42             : struct sss_child_ctx {
      43             :     pid_t pid;
      44             :     sss_child_fn_t cb;
      45             :     void *pvt;
      46             :     struct sss_sigchild_ctx *sigchld_ctx;
      47             : };
      48             : 
      49             : static void sss_child_handler(struct tevent_context *ev,
      50             :                               struct tevent_signal *se,
      51             :                               int signum,
      52             :                               int count,
      53             :                               void *siginfo,
      54             :                               void *private_data);
      55             : 
      56           1 : errno_t sss_sigchld_init(TALLOC_CTX *mem_ctx,
      57             :                          struct tevent_context *ev,
      58             :                          struct sss_sigchild_ctx **child_ctx)
      59             : {
      60             :     errno_t ret;
      61             :     struct sss_sigchild_ctx *sigchld_ctx;
      62             :     struct tevent_signal *tes;
      63             : 
      64           1 :     sigchld_ctx = talloc_zero(mem_ctx, struct sss_sigchild_ctx);
      65           1 :     if (!sigchld_ctx) {
      66           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
      67             :               "fatal error initializing sss_sigchild_ctx\n");
      68           0 :         return ENOMEM;
      69             :     }
      70           1 :     sigchld_ctx->ev = ev;
      71             : 
      72           1 :     ret = sss_hash_create(sigchld_ctx, 10, &sigchld_ctx->children);
      73           1 :     if (ret != EOK) {
      74           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
      75             :               "fatal error initializing children hash table: [%s]\n",
      76             :                strerror(ret));
      77           0 :         talloc_free(sigchld_ctx);
      78           0 :         return ret;
      79             :     }
      80             : 
      81           1 :     BlockSignals(false, SIGCHLD);
      82           1 :     tes = tevent_add_signal(ev, sigchld_ctx, SIGCHLD, SA_SIGINFO,
      83             :                             sss_child_handler, sigchld_ctx);
      84           1 :     if (tes == NULL) {
      85           0 :         talloc_free(sigchld_ctx);
      86           0 :         return EIO;
      87             :     }
      88             : 
      89           1 :     *child_ctx = sigchld_ctx;
      90           1 :     return EOK;
      91             : }
      92             : 
      93           1 : static int sss_child_destructor(void *ptr)
      94             : {
      95             :     struct sss_child_ctx *child_ctx;
      96             :     hash_key_t key;
      97             :     int error;
      98             : 
      99           1 :     child_ctx = talloc_get_type(ptr, struct sss_child_ctx);
     100           1 :     key.type = HASH_KEY_ULONG;
     101           1 :     key.ul = child_ctx->pid;
     102             : 
     103           1 :     error = hash_delete(child_ctx->sigchld_ctx->children, &key);
     104           1 :     if (error != HASH_SUCCESS && error != HASH_ERROR_KEY_NOT_FOUND) {
     105           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     106             :               "failed to delete child_ctx from hash table [%d]: %s\n",
     107             :                error, hash_error_string(error));
     108             :     }
     109             : 
     110           1 :     return 0;
     111             : }
     112             : 
     113           1 : errno_t sss_child_register(TALLOC_CTX *mem_ctx,
     114             :                            struct sss_sigchild_ctx *sigchld_ctx,
     115             :                            pid_t pid,
     116             :                            sss_child_fn_t cb,
     117             :                            void *pvt,
     118             :                            struct sss_child_ctx **child_ctx)
     119             : {
     120             :     struct sss_child_ctx *child;
     121             :     hash_key_t key;
     122             :     hash_value_t value;
     123             :     int error;
     124             : 
     125           1 :     child = talloc_zero(mem_ctx, struct sss_child_ctx);
     126           1 :     if (child == NULL) {
     127           0 :         return ENOMEM;
     128             :     }
     129             : 
     130           1 :     child->pid = pid;
     131           1 :     child->cb = cb;
     132           1 :     child->pvt = pvt;
     133           1 :     child->sigchld_ctx = sigchld_ctx;
     134             : 
     135           1 :     key.type = HASH_KEY_ULONG;
     136           1 :     key.ul = pid;
     137             : 
     138           1 :     value.type = HASH_VALUE_PTR;
     139           1 :     value.ptr = child;
     140             : 
     141           1 :     error = hash_enter(sigchld_ctx->children, &key, &value);
     142           1 :     if (error != HASH_SUCCESS) {
     143           0 :         talloc_free(child);
     144           0 :         return ENOMEM;
     145             :     }
     146             : 
     147           1 :     talloc_set_destructor((TALLOC_CTX *) child, sss_child_destructor);
     148             : 
     149           1 :     *child_ctx = child;
     150           1 :     return EOK;
     151             : }
     152             : 
     153             : struct sss_child_cb_pvt {
     154             :     struct sss_child_ctx *child_ctx;
     155             :     int wait_status;
     156             : };
     157             : 
     158           1 : static void sss_child_invoke_cb(struct tevent_context *ev,
     159             :                                 struct tevent_immediate *imm,
     160             :                                 void *pvt)
     161             : {
     162             :     struct sss_child_cb_pvt *cb_pvt;
     163             :     struct sss_child_ctx *child_ctx;
     164             :     hash_key_t key;
     165             :     int error;
     166             : 
     167           1 :     cb_pvt = talloc_get_type(pvt, struct sss_child_cb_pvt);
     168           1 :     child_ctx = cb_pvt->child_ctx;
     169             : 
     170           1 :     key.type = HASH_KEY_ULONG;
     171           1 :     key.ul = child_ctx->pid;
     172             : 
     173           1 :     error = hash_delete(child_ctx->sigchld_ctx->children, &key);
     174           1 :     if (error != HASH_SUCCESS && error != HASH_ERROR_KEY_NOT_FOUND) {
     175           0 :         DEBUG(SSSDBG_OP_FAILURE,
     176             :               "failed to delete child_ctx from hash table [%d]: %s\n",
     177             :                error, hash_error_string(error));
     178             :     }
     179             : 
     180           1 :     if (child_ctx->cb) {
     181           1 :         child_ctx->cb(child_ctx->pid, cb_pvt->wait_status, child_ctx->pvt);
     182             :     }
     183             : 
     184           1 :     talloc_free(imm);
     185           1 : }
     186             : 
     187           1 : static void sss_child_handler(struct tevent_context *ev,
     188             :                               struct tevent_signal *se,
     189             :                               int signum,
     190             :                               int count,
     191             :                               void *siginfo,
     192             :                               void *private_data)
     193             : {
     194             :     struct sss_sigchild_ctx *sigchld_ctx;
     195             :     struct tevent_immediate *imm;
     196             :     struct sss_child_cb_pvt *invoke_pvt;
     197             :     struct sss_child_ctx *child_ctx;
     198             :     hash_key_t key;
     199             :     hash_value_t value;
     200             :     int error;
     201             :     int wait_status;
     202             :     pid_t pid;
     203             : 
     204           1 :     sigchld_ctx = talloc_get_type(private_data, struct sss_sigchild_ctx);
     205           1 :     key.type = HASH_KEY_ULONG;
     206             : 
     207             :     do {
     208             :         do {
     209           2 :             errno = 0;
     210           2 :             pid = waitpid(-1, &wait_status, WNOHANG | sigchld_ctx->options);
     211           2 :         } while (pid == -1 && errno == EINTR);
     212             : 
     213           2 :         if (pid == -1) {
     214           1 :             DEBUG(SSSDBG_TRACE_INTERNAL,
     215             :                   "waitpid failed [%d]: %s\n", errno, strerror(errno));
     216           2 :             return;
     217           1 :         } else if (pid == 0) continue;
     218             : 
     219           1 :         key.ul = pid;
     220           1 :         error = hash_lookup(sigchld_ctx->children, &key, &value);
     221           1 :         if (error == HASH_SUCCESS) {
     222           1 :             child_ctx = talloc_get_type(value.ptr, struct sss_child_ctx);
     223             : 
     224           1 :             imm = tevent_create_immediate(child_ctx);
     225           1 :             if (imm == NULL) {
     226           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     227             :                       "Out of memory invoking SIGCHLD callback\n");
     228           0 :                 return;
     229             :             }
     230             : 
     231           1 :             invoke_pvt = talloc_zero(child_ctx, struct sss_child_cb_pvt);
     232           1 :             if (invoke_pvt == NULL) {
     233           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     234             :                       "out of memory invoking SIGCHLD callback\n");
     235           0 :                 return;
     236             :             }
     237           1 :             invoke_pvt->child_ctx = child_ctx;
     238           1 :             invoke_pvt->wait_status = wait_status;
     239             : 
     240           1 :             tevent_schedule_immediate(imm, sigchld_ctx->ev,
     241             :                                       sss_child_invoke_cb, invoke_pvt);
     242           0 :         } else if (error == HASH_ERROR_KEY_NOT_FOUND) {
     243           0 :             DEBUG(SSSDBG_TRACE_LIBS,
     244             :                  "BUG: waitpid() returned [%d] but it was not in the table. "
     245             :                   "This could be due to a linked library creating processes "
     246             :                   "without registering them with the sigchld handler\n",
     247             :                   pid);
     248             :             /* We will simply ignore this and return to the loop
     249             :              * This will prevent a zombie, but may cause unexpected
     250             :              * behavior in the code that was trying to handle this
     251             :              * pid.
     252             :              */
     253             :         } else {
     254           0 :             DEBUG(SSSDBG_OP_FAILURE,
     255             :                   "SIGCHLD hash table error [%d]: %s\n",
     256             :                    error, hash_error_string(error));
     257             :             /* This is bad, but we should try to check for other
     258             :              * children anyway, to avoid potential zombies.
     259             :              */
     260             :         }
     261           1 :     } while (pid != 0);
     262             : }
     263             : 
     264             : struct sss_child_ctx_old {
     265             :     struct tevent_signal *sige;
     266             :     pid_t pid;
     267             :     int child_status;
     268             :     sss_child_callback_t cb;
     269             :     void *pvt;
     270             : };
     271             : 
     272             : static void child_sig_handler(struct tevent_context *ev,
     273             :                               struct tevent_signal *sige, int signum,
     274             :                               int count, void *__siginfo, void *pvt);
     275             : 
     276          14 : int child_handler_setup(struct tevent_context *ev, int pid,
     277             :                         sss_child_callback_t cb, void *pvt,
     278             :                         struct sss_child_ctx_old **_child_ctx)
     279             : {
     280             :     struct sss_child_ctx_old *child_ctx;
     281             : 
     282          14 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     283             :           "Setting up signal handler up for pid [%d]\n", pid);
     284             : 
     285          14 :     child_ctx = talloc_zero(ev, struct sss_child_ctx_old);
     286          14 :     if (child_ctx == NULL) {
     287           0 :         return ENOMEM;
     288             :     }
     289             : 
     290          14 :     child_ctx->sige = tevent_add_signal(ev, child_ctx, SIGCHLD, SA_SIGINFO,
     291             :                                         child_sig_handler, child_ctx);
     292          14 :     if(!child_ctx->sige) {
     293             :         /* Error setting up signal handler */
     294           0 :         talloc_free(child_ctx);
     295           0 :         return ENOMEM;
     296             :     }
     297             : 
     298          14 :     child_ctx->pid = pid;
     299          14 :     child_ctx->cb = cb;
     300          14 :     child_ctx->pvt = pvt;
     301             : 
     302          14 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Signal handler set up for pid [%d]\n", pid);
     303             : 
     304          14 :     if (_child_ctx != NULL) {
     305          13 :         *_child_ctx = child_ctx;
     306             :     }
     307             : 
     308          14 :     return EOK;
     309             : }
     310             : 
     311           1 : void child_handler_destroy(struct sss_child_ctx_old *ctx)
     312             : {
     313             :     errno_t ret;
     314             : 
     315             :     /* We still want to wait for the child to finish, but the caller is not
     316             :      * interested in the result anymore (e.g. timeout was reached). */
     317           1 :     ctx->cb = NULL;
     318           1 :     ctx->pvt = NULL;
     319             : 
     320           1 :     ret = kill(ctx->pid, SIGKILL);
     321           1 :     if (ret == -1) {
     322           0 :         ret = errno;
     323           0 :         DEBUG(SSSDBG_MINOR_FAILURE, "kill failed [%d][%s].\n", ret, strerror(ret));
     324             :     }
     325           1 : }
     326             : 
     327             : /* Async communication with the child process via a pipe */
     328             : 
     329             : struct write_pipe_state {
     330             :     int fd;
     331             :     uint8_t *buf;
     332             :     size_t len;
     333             :     ssize_t written;
     334             : };
     335             : 
     336             : static void write_pipe_handler(struct tevent_context *ev,
     337             :                                struct tevent_fd *fde,
     338             :                                uint16_t flags, void *pvt);
     339             : 
     340           6 : struct tevent_req *write_pipe_send(TALLOC_CTX *mem_ctx,
     341             :                                    struct tevent_context *ev,
     342             :                                    uint8_t *buf, size_t len, int fd)
     343             : {
     344             :     struct tevent_req *req;
     345             :     struct write_pipe_state *state;
     346             :     struct tevent_fd *fde;
     347             : 
     348           6 :     req = tevent_req_create(mem_ctx, &state, struct write_pipe_state);
     349           6 :     if (req == NULL) return NULL;
     350             : 
     351           6 :     state->fd = fd;
     352           6 :     state->buf = buf;
     353           6 :     state->len = len;
     354           6 :     state->written = 0;
     355             : 
     356           6 :     fde = tevent_add_fd(ev, state, fd, TEVENT_FD_WRITE,
     357             :                         write_pipe_handler, req);
     358           6 :     if (fde == NULL) {
     359           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
     360           0 :         goto fail;
     361             :     }
     362             : 
     363           6 :     return req;
     364             : 
     365             : fail:
     366           0 :     talloc_zfree(req);
     367           0 :     return NULL;
     368             : }
     369             : 
     370           6 : static void write_pipe_handler(struct tevent_context *ev,
     371             :                                struct tevent_fd *fde,
     372             :                                uint16_t flags, void *pvt)
     373             : {
     374           6 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     375           6 :     struct write_pipe_state *state = tevent_req_data(req,
     376             :                                                      struct write_pipe_state);
     377             :     errno_t ret;
     378             : 
     379           6 :     if (flags & TEVENT_FD_READ) {
     380           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     381             :               "write_pipe_done called with TEVENT_FD_READ,"
     382             :                " this should not happen.\n");
     383           0 :         tevent_req_error(req, EINVAL);
     384           0 :         return;
     385             :     }
     386             : 
     387           6 :     errno = 0;
     388           6 :     state->written = sss_atomic_write_s(state->fd, state->buf, state->len);
     389           6 :     if (state->written == -1) {
     390           0 :         ret = errno;
     391           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     392             :               "write failed [%d][%s].\n", ret, strerror(ret));
     393           0 :         tevent_req_error(req, ret);
     394           0 :         return;
     395             :     }
     396             : 
     397           6 :     if (state->len != state->written) {
     398           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Wrote %zd bytes, expected %zu\n",
     399             :               state->written, state->len);
     400           0 :         tevent_req_error(req, EIO);
     401           0 :         return;
     402             :     }
     403             : 
     404           6 :     DEBUG(SSSDBG_TRACE_FUNC, "All data has been sent!\n");
     405           6 :     tevent_req_done(req);
     406           6 :     return;
     407             : }
     408             : 
     409           6 : int write_pipe_recv(struct tevent_req *req)
     410             : {
     411           6 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     412             : 
     413           6 :     return EOK;
     414             : }
     415             : 
     416             : struct read_pipe_state {
     417             :     int fd;
     418             :     uint8_t *buf;
     419             :     size_t len;
     420             : };
     421             : 
     422             : static void read_pipe_handler(struct tevent_context *ev,
     423             :                               struct tevent_fd *fde,
     424             :                               uint16_t flags, void *pvt);
     425             : 
     426          10 : struct tevent_req *read_pipe_send(TALLOC_CTX *mem_ctx,
     427             :                                   struct tevent_context *ev, int fd)
     428             : {
     429             :     struct tevent_req *req;
     430             :     struct read_pipe_state *state;
     431             :     struct tevent_fd *fde;
     432             : 
     433          10 :     req = tevent_req_create(mem_ctx, &state, struct read_pipe_state);
     434          10 :     if (req == NULL) return NULL;
     435             : 
     436          10 :     state->fd = fd;
     437          10 :     state->buf = NULL;
     438          10 :     state->len = 0;
     439             : 
     440          10 :     fde = tevent_add_fd(ev, state, fd, TEVENT_FD_READ,
     441             :                         read_pipe_handler, req);
     442          10 :     if (fde == NULL) {
     443           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_fd failed.\n");
     444           0 :         goto fail;
     445             :     }
     446             : 
     447          10 :     return req;
     448             : 
     449             : fail:
     450           0 :     talloc_zfree(req);
     451           0 :     return NULL;
     452             : }
     453             : 
     454          53 : static void read_pipe_handler(struct tevent_context *ev,
     455             :                               struct tevent_fd *fde,
     456             :                               uint16_t flags, void *pvt)
     457             : {
     458          53 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     459          53 :     struct read_pipe_state *state = tevent_req_data(req,
     460             :                                                     struct read_pipe_state);
     461             :     ssize_t size;
     462             :     errno_t err;
     463             :     uint8_t buf[CHILD_MSG_CHUNK];
     464             : 
     465          53 :     if (flags & TEVENT_FD_WRITE) {
     466           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "read_pipe_done called with TEVENT_FD_WRITE,"
     467             :                   " this should not happen.\n");
     468           0 :         tevent_req_error(req, EINVAL);
     469           0 :         return;
     470             :     }
     471             : 
     472          53 :     size = sss_atomic_read_s(state->fd,
     473             :                 buf,
     474             :                 CHILD_MSG_CHUNK);
     475          53 :     if (size == -1) {
     476           0 :         err = errno;
     477           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     478             :               "read failed [%d][%s].\n", err, strerror(err));
     479           0 :         tevent_req_error(req, err);
     480           0 :         return;
     481             : 
     482          53 :     } else if (size > 0) {
     483          43 :         state->buf = talloc_realloc(state, state->buf, uint8_t,
     484             :                                     state->len + size);
     485          43 :         if(!state->buf) {
     486           0 :             tevent_req_error(req, ENOMEM);
     487           0 :             return;
     488             :         }
     489             : 
     490          43 :         safealign_memcpy(&state->buf[state->len], buf,
     491             :                          size, &state->len);
     492          43 :         return;
     493             : 
     494          10 :     } else if (size == 0) {
     495          10 :         DEBUG(SSSDBG_TRACE_FUNC, "EOF received, client finished\n");
     496          10 :         tevent_req_done(req);
     497          10 :         return;
     498             : 
     499             :     } else {
     500           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     501             :               "unexpected return value of read [%zd].\n", size);
     502           0 :         tevent_req_error(req, EINVAL);
     503           0 :         return;
     504             :     }
     505             : }
     506             : 
     507          10 : int read_pipe_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     508             :                    uint8_t **buf, ssize_t *len)
     509             : {
     510             :     struct read_pipe_state *state;
     511          10 :     state = tevent_req_data(req, struct read_pipe_state);
     512             : 
     513          10 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     514             : 
     515          10 :     *buf = talloc_steal(mem_ctx, state->buf);
     516          10 :     *len = state->len;
     517             : 
     518          10 :     return EOK;
     519             : }
     520             : 
     521             : static void child_invoke_callback(struct tevent_context *ev,
     522             :                                   struct tevent_immediate *imm,
     523             :                                   void *pvt);
     524          14 : static void child_sig_handler(struct tevent_context *ev,
     525             :                               struct tevent_signal *sige, int signum,
     526             :                               int count, void *__siginfo, void *pvt)
     527             : {
     528             :     int ret, err;
     529             :     struct sss_child_ctx_old *child_ctx;
     530             :     struct tevent_immediate *imm;
     531             : 
     532          14 :     if (count <= 0) {
     533           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     534             :               "SIGCHLD handler called with invalid child count\n");
     535           0 :         return;
     536             :     }
     537             : 
     538          14 :     child_ctx = talloc_get_type(pvt, struct sss_child_ctx_old);
     539          14 :     DEBUG(SSSDBG_TRACE_LIBS, "Waiting for child [%d].\n", child_ctx->pid);
     540             : 
     541          14 :     errno = 0;
     542          14 :     ret = waitpid(child_ctx->pid, &child_ctx->child_status, WNOHANG);
     543             : 
     544          14 :     if (ret == -1) {
     545           0 :         err = errno;
     546           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     547             :               "waitpid failed [%d][%s].\n", err, strerror(err));
     548          14 :     } else if (ret == 0) {
     549           2 :         DEBUG(SSSDBG_CRIT_FAILURE,
     550             :               "waitpid did not found a child with changed status.\n");
     551             :     } else {
     552          12 :         if (WIFEXITED(child_ctx->child_status)) {
     553          11 :             if (WEXITSTATUS(child_ctx->child_status) != 0) {
     554           1 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     555             :                       "child [%d] failed with status [%d].\n", ret,
     556             :                           WEXITSTATUS(child_ctx->child_status));
     557             :             } else {
     558          10 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     559             :                       "child [%d] finished successfully.\n", ret);
     560             :             }
     561           1 :         } else if (WIFSIGNALED(child_ctx->child_status)) {
     562           1 :             DEBUG(SSSDBG_CRIT_FAILURE,
     563             :                   "child [%d] was terminated by signal [%d].\n", ret,
     564             :                       WTERMSIG(child_ctx->child_status));
     565             :         } else {
     566           0 :             if (WIFSTOPPED(child_ctx->child_status)) {
     567           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
     568             :                       "child [%d] was stopped by signal [%d].\n", ret,
     569             :                           WSTOPSIG(child_ctx->child_status));
     570             :             }
     571           0 :             if (WIFCONTINUED(child_ctx->child_status) == true) {
     572           0 :                 DEBUG(SSSDBG_TRACE_LIBS,
     573             :                       "child [%d] was resumed by delivery of SIGCONT.\n",
     574             :                           ret);
     575             :             }
     576             : 
     577           0 :             return;
     578             :         }
     579             : 
     580             :         /* Invoke the callback in a tevent_immediate handler
     581             :          * so that it is safe to free the tevent_signal *
     582             :          */
     583          12 :         imm = tevent_create_immediate(child_ctx);
     584          12 :         if (imm == NULL) {
     585           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     586             :                   "Out of memory invoking sig handler callback\n");
     587           0 :             return;
     588             :         }
     589             : 
     590          12 :         tevent_schedule_immediate(imm, ev, child_invoke_callback,
     591             :                                   child_ctx);
     592             :     }
     593             : 
     594          14 :     return;
     595             : }
     596             : 
     597           5 : static void child_invoke_callback(struct tevent_context *ev,
     598             :                                   struct tevent_immediate *imm,
     599             :                                   void *pvt)
     600             : {
     601           5 :     struct sss_child_ctx_old *child_ctx =
     602             :             talloc_get_type(pvt, struct sss_child_ctx_old);
     603           5 :     if (child_ctx->cb) {
     604           3 :         child_ctx->cb(child_ctx->child_status, child_ctx->sige, child_ctx->pvt);
     605             :     }
     606             : 
     607             :     /* Stop monitoring for this child */
     608           5 :     talloc_free(child_ctx);
     609           5 : }
     610             : 
     611           0 : static errno_t prepare_child_argv(TALLOC_CTX *mem_ctx,
     612             :                                   int child_debug_fd,
     613             :                                   const char *binary,
     614             :                                   const char *extra_argv[],
     615             :                                   bool extra_args_only,
     616             :                                   char ***_argv)
     617             : {
     618             :     /*
     619             :      * program name, debug_level, debug_timestamps,
     620             :      * debug_microseconds and NULL
     621             :      */
     622           0 :     uint_t argc = 5;
     623           0 :     char ** argv = NULL;
     624           0 :     errno_t ret = EINVAL;
     625             :     size_t i;
     626             : 
     627           0 :     if (extra_args_only) {
     628           0 :         argc = 2; /* program name and NULL */
     629             :     }
     630             : 
     631             :     /* Save the current state in case an interrupt changes it */
     632           0 :     bool child_debug_to_file = debug_to_file;
     633           0 :     bool child_debug_timestamps = debug_timestamps;
     634           0 :     bool child_debug_microseconds = debug_microseconds;
     635           0 :     bool child_debug_stderr = debug_to_stderr;
     636             : 
     637           0 :     if (!extra_args_only) {
     638           0 :         if (child_debug_to_file) argc++;
     639           0 :         if (child_debug_stderr) argc++;
     640             :     }
     641             : 
     642           0 :     if (extra_argv) {
     643           0 :         for (i = 0; extra_argv[i]; i++) argc++;
     644             :     }
     645             : 
     646             :     /*
     647             :      * program name, debug_level, debug_to_file, debug_timestamps,
     648             :      * debug_microseconds and NULL
     649             :      */
     650           0 :     argv  = talloc_array(mem_ctx, char *, argc);
     651           0 :     if (argv == NULL) {
     652           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_array failed.\n");
     653           0 :         return ENOMEM;
     654             :     }
     655             : 
     656           0 :     argv[--argc] = NULL;
     657             : 
     658             :     /* Add extra_attrs first */
     659           0 :     if (extra_argv) {
     660           0 :         for (i = 0; extra_argv[i]; i++) {
     661           0 :             argv[--argc] = talloc_strdup(argv, extra_argv[i]);
     662           0 :             if (argv[argc] == NULL) {
     663           0 :                 ret = ENOMEM;
     664           0 :                 goto fail;
     665             :             }
     666             :         }
     667             :     }
     668             : 
     669           0 :     if (!extra_args_only) {
     670           0 :         argv[--argc] = talloc_asprintf(argv, "--debug-level=%#.4x",
     671             :                                   debug_level);
     672           0 :         if (argv[argc] == NULL) {
     673           0 :             ret = ENOMEM;
     674           0 :             goto fail;
     675             :         }
     676             : 
     677           0 :         if (child_debug_stderr) {
     678           0 :             argv[--argc] = talloc_strdup(argv, "--debug-to-stderr");
     679           0 :             if (argv[argc] == NULL) {
     680           0 :                 ret = ENOMEM;
     681           0 :                 goto fail;
     682             :             }
     683             :         }
     684             : 
     685           0 :         if (child_debug_to_file) {
     686           0 :             argv[--argc] = talloc_asprintf(argv, "--debug-fd=%d",
     687             :                                            child_debug_fd);
     688           0 :             if (argv[argc] == NULL) {
     689           0 :                 ret = ENOMEM;
     690           0 :                 goto fail;
     691             :             }
     692             :         }
     693             : 
     694           0 :         argv[--argc] = talloc_asprintf(argv, "--debug-timestamps=%d",
     695             :                                        child_debug_timestamps);
     696           0 :         if (argv[argc] == NULL) {
     697           0 :             ret = ENOMEM;
     698           0 :             goto fail;
     699             :         }
     700             : 
     701           0 :         argv[--argc] = talloc_asprintf(argv, "--debug-microseconds=%d",
     702             :                                            child_debug_microseconds);
     703           0 :         if (argv[argc] == NULL) {
     704           0 :             ret = ENOMEM;
     705           0 :             goto fail;
     706             :         }
     707             :     }
     708             : 
     709           0 :     argv[--argc] = talloc_strdup(argv, binary);
     710           0 :     if (argv[argc] == NULL) {
     711           0 :         ret = ENOMEM;
     712           0 :         goto fail;
     713             :     }
     714             : 
     715           0 :     if (argc != 0) {
     716           0 :         ret = EINVAL;
     717           0 :         goto fail;
     718             :     }
     719             : 
     720           0 :     *_argv = argv;
     721             : 
     722           0 :     return EOK;
     723             : 
     724             : fail:
     725           0 :     talloc_free(argv);
     726           0 :     return ret;
     727             : }
     728             : 
     729           0 : void exec_child_ex(TALLOC_CTX *mem_ctx,
     730             :                    int *pipefd_to_child, int *pipefd_from_child,
     731             :                    const char *binary, int debug_fd,
     732             :                    const char *extra_argv[], bool extra_args_only,
     733             :                    int child_in_fd, int child_out_fd)
     734             : {
     735             :     int ret;
     736             :     errno_t err;
     737             :     char **argv;
     738             : 
     739           0 :     close(pipefd_to_child[1]);
     740           0 :     ret = dup2(pipefd_to_child[0], child_in_fd);
     741           0 :     if (ret == -1) {
     742           0 :         err = errno;
     743           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     744             :               "dup2 failed [%d][%s].\n", err, strerror(err));
     745           0 :         exit(EXIT_FAILURE);
     746             :     }
     747             : 
     748           0 :     close(pipefd_from_child[0]);
     749           0 :     ret = dup2(pipefd_from_child[1], child_out_fd);
     750           0 :     if (ret == -1) {
     751           0 :         err = errno;
     752           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     753             :               "dup2 failed [%d][%s].\n", err, strerror(err));
     754           0 :         exit(EXIT_FAILURE);
     755             :     }
     756             : 
     757           0 :     ret = prepare_child_argv(mem_ctx, debug_fd,
     758             :                              binary, extra_argv, extra_args_only,
     759             :                              &argv);
     760           0 :     if (ret != EOK) {
     761           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "prepare_child_argv.\n");
     762           0 :         exit(EXIT_FAILURE);
     763             :     }
     764             : 
     765           0 :     execv(binary, argv);
     766           0 :     err = errno;
     767           0 :     DEBUG(SSSDBG_OP_FAILURE, "execv failed [%d][%s].\n", err, strerror(err));
     768           0 :     exit(EXIT_FAILURE);
     769             : }
     770             : 
     771           0 : void exec_child(TALLOC_CTX *mem_ctx,
     772             :                 int *pipefd_to_child, int *pipefd_from_child,
     773             :                 const char *binary, int debug_fd)
     774             : {
     775           0 :     exec_child_ex(mem_ctx, pipefd_to_child, pipefd_from_child,
     776             :                   binary, debug_fd, NULL, false,
     777             :                   STDIN_FILENO, STDOUT_FILENO);
     778           0 : }
     779             : 
     780          11 : int child_io_destructor(void *ptr)
     781             : {
     782             :     int ret;
     783          11 :     struct child_io_fds *io = talloc_get_type(ptr, struct child_io_fds);
     784          11 :     if (io == NULL) return EOK;
     785             : 
     786          11 :     if (io->write_to_child_fd != -1) {
     787           8 :         ret = close(io->write_to_child_fd);
     788           8 :         io->write_to_child_fd = -1;
     789           8 :         if (ret != EOK) {
     790           0 :             ret = errno;
     791           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     792             :                   "close failed [%d][%s].\n", ret, strerror(ret));
     793             :         }
     794             :     }
     795             : 
     796          11 :     if (io->read_from_child_fd != -1) {
     797           1 :         ret = close(io->read_from_child_fd);
     798           1 :         io->read_from_child_fd = -1;
     799           1 :         if (ret != EOK) {
     800           0 :             ret = errno;
     801           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     802             :                   "close failed [%d][%s].\n", ret, strerror(ret));
     803             :         }
     804             :     }
     805             : 
     806          11 :     return EOK;
     807             : }
     808             : 
     809           0 : errno_t child_debug_init(const char *logfile, int *debug_fd)
     810             : {
     811             :     int ret;
     812             :     FILE *debug_filep;
     813             : 
     814           0 :     if (debug_fd == NULL) {
     815           0 :         return EOK;
     816             :     }
     817             : 
     818           0 :     if (debug_to_file != 0 && *debug_fd == -1) {
     819           0 :         ret = open_debug_file_ex(logfile, &debug_filep, false);
     820           0 :         if (ret != EOK) {
     821           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Error setting up logging (%d) [%s]\n",
     822             :                         ret, sss_strerror(ret));
     823           0 :             return ret;
     824             :         }
     825             : 
     826           0 :         *debug_fd = fileno(debug_filep);
     827           0 :         if (*debug_fd == -1) {
     828           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     829             :                   "fileno failed [%d][%s]\n", errno, strerror(errno));
     830           0 :             ret = errno;
     831           0 :             return ret;
     832             :         }
     833             :     }
     834             : 
     835           0 :     return EOK;
     836             : }

Generated by: LCOV version 1.10