LCOV - code coverage report
Current view: top level - providers/ldap - sdap_child_helpers.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 196 0.0 %
Date: 2016-06-29 Functions: 0 11 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     LDAP Backend Module -- child helpers
       5             : 
       6             :     Authors:
       7             :         Jakub Hrozek <jhrozek@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 <sys/wait.h>
      27             : #include <pwd.h>
      28             : #include <unistd.h>
      29             : #include <fcntl.h>
      30             : 
      31             : #include "util/util.h"
      32             : #include "util/sss_krb5.h"
      33             : #include "providers/ldap/ldap_common.h"
      34             : #include "providers/ldap/sdap_async_private.h"
      35             : #include "util/child_common.h"
      36             : 
      37             : #ifndef SSSD_LIBEXEC_PATH
      38             : #error "SSSD_LIBEXEC_PATH not defined"
      39             : #else
      40             : #define LDAP_CHILD SSSD_LIBEXEC_PATH"/ldap_child"
      41             : #endif
      42             : 
      43             : #ifndef LDAP_CHILD_USER
      44             : #define LDAP_CHILD_USER  "nobody"
      45             : #endif
      46             : 
      47             : struct sdap_child {
      48             :     /* child info */
      49             :     pid_t pid;
      50             :     struct child_io_fds *io;
      51             : };
      52             : 
      53           0 : static void sdap_close_fd(int *fd)
      54             : {
      55             :     int ret;
      56             : 
      57           0 :     if (*fd == -1) {
      58           0 :         DEBUG(SSSDBG_TRACE_FUNC, "fd already closed\n");
      59           0 :         return;
      60             :     }
      61             : 
      62           0 :     ret = close(*fd);
      63           0 :     if (ret) {
      64           0 :         ret = errno;
      65           0 :         DEBUG(SSSDBG_OP_FAILURE, "Closing fd %d, return error %d (%s)\n",
      66             :                   *fd, ret, strerror(ret));
      67             :     }
      68             : 
      69           0 :     *fd = -1;
      70             : }
      71             : 
      72           0 : static errno_t sdap_fork_child(struct tevent_context *ev,
      73             :                                struct sdap_child *child)
      74             : {
      75           0 :     int pipefd_to_child[2] = PIPE_INIT;
      76           0 :     int pipefd_from_child[2] = PIPE_INIT;
      77             :     pid_t pid;
      78             :     errno_t ret;
      79             : 
      80           0 :     ret = pipe(pipefd_from_child);
      81           0 :     if (ret == -1) {
      82           0 :         ret = errno;
      83           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      84             :               "pipe failed [%d][%s].\n", ret, strerror(ret));
      85           0 :         goto fail;
      86             :     }
      87           0 :     ret = pipe(pipefd_to_child);
      88           0 :     if (ret == -1) {
      89           0 :         ret = errno;
      90           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      91             :               "pipe failed [%d][%s].\n", ret, strerror(ret));
      92           0 :         goto fail;
      93             :     }
      94             : 
      95           0 :     pid = fork();
      96             : 
      97           0 :     if (pid == 0) { /* child */
      98           0 :         exec_child(child,
      99             :                    pipefd_to_child, pipefd_from_child,
     100             :                    LDAP_CHILD, ldap_child_debug_fd);
     101             : 
     102             :         /* We should never get here */
     103           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec LDAP child\n");
     104           0 :     } else if (pid > 0) { /* parent */
     105           0 :         child->pid = pid;
     106           0 :         child->io->read_from_child_fd = pipefd_from_child[0];
     107           0 :         PIPE_FD_CLOSE(pipefd_from_child[1]);
     108           0 :         child->io->write_to_child_fd = pipefd_to_child[1];
     109           0 :         PIPE_FD_CLOSE(pipefd_to_child[0]);
     110           0 :         sss_fd_nonblocking(child->io->read_from_child_fd);
     111           0 :         sss_fd_nonblocking(child->io->write_to_child_fd);
     112             : 
     113           0 :         ret = child_handler_setup(ev, pid, NULL, NULL, NULL);
     114           0 :         if (ret != EOK) {
     115           0 :             goto fail;
     116             :         }
     117             : 
     118             :     } else { /* error */
     119           0 :         ret = errno;
     120           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     121             :               "fork failed [%d][%s].\n", ret, strerror(ret));
     122           0 :         goto fail;
     123             :     }
     124             : 
     125           0 :     return EOK;
     126             : 
     127             : fail:
     128           0 :     PIPE_CLOSE(pipefd_from_child);
     129           0 :     PIPE_CLOSE(pipefd_to_child);
     130           0 :     return ret;
     131             : }
     132             : 
     133           0 : static errno_t create_tgt_req_send_buffer(TALLOC_CTX *mem_ctx,
     134             :                                           const char *realm_str,
     135             :                                           const char *princ_str,
     136             :                                           const char *keytab_name,
     137             :                                           int32_t lifetime,
     138             :                                           struct io_buffer **io_buf)
     139             : {
     140             :     struct io_buffer *buf;
     141             :     size_t rp;
     142             : 
     143           0 :     buf = talloc(mem_ctx, struct io_buffer);
     144           0 :     if (buf == NULL) {
     145           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     146           0 :         return ENOMEM;
     147             :     }
     148             : 
     149           0 :     buf->size = 6 * sizeof(uint32_t);
     150           0 :     if (realm_str) {
     151           0 :         buf->size += strlen(realm_str);
     152             :     }
     153           0 :     if (princ_str) {
     154           0 :         buf->size += strlen(princ_str);
     155             :     }
     156           0 :     if (keytab_name) {
     157           0 :         buf->size += strlen(keytab_name);
     158             :     }
     159             : 
     160           0 :     DEBUG(SSSDBG_TRACE_FUNC, "buffer size: %zu\n", buf->size);
     161             : 
     162           0 :     buf->data = talloc_size(buf, buf->size);
     163           0 :     if (buf->data == NULL) {
     164           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
     165           0 :         talloc_free(buf);
     166           0 :         return ENOMEM;
     167             :     }
     168             : 
     169           0 :     rp = 0;
     170             : 
     171             :     /* realm */
     172           0 :     if (realm_str) {
     173           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(realm_str), &rp);
     174           0 :         safealign_memcpy(&buf->data[rp], realm_str, strlen(realm_str), &rp);
     175             :     } else {
     176           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
     177             :     }
     178             : 
     179             :     /* principal */
     180           0 :     if (princ_str) {
     181           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(princ_str), &rp);
     182           0 :         safealign_memcpy(&buf->data[rp], princ_str, strlen(princ_str), &rp);
     183             :     } else {
     184           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
     185             :     }
     186             : 
     187             :     /* keytab */
     188           0 :     if (keytab_name) {
     189           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab_name), &rp);
     190           0 :         safealign_memcpy(&buf->data[rp], keytab_name, strlen(keytab_name), &rp);
     191             :     } else {
     192           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
     193             :     }
     194             : 
     195             :     /* lifetime */
     196           0 :     SAFEALIGN_SET_UINT32(&buf->data[rp], lifetime, &rp);
     197             : 
     198             :     /* UID and GID to drop privileges to, if needed. The ldap_child process runs as
     199             :      * setuid if the back end runs unprivileged as it needs to access the keytab
     200             :      */
     201           0 :     SAFEALIGN_SET_UINT32(&buf->data[rp], geteuid(), &rp);
     202           0 :     SAFEALIGN_SET_UINT32(&buf->data[rp], getegid(), &rp);
     203             : 
     204           0 :     *io_buf = buf;
     205           0 :     return EOK;
     206             : }
     207             : 
     208           0 : static int parse_child_response(TALLOC_CTX *mem_ctx,
     209             :                                 uint8_t *buf, ssize_t size,
     210             :                                 int  *result, krb5_error_code *kerr,
     211             :                                 char **ccache, time_t *expire_time_out)
     212             : {
     213           0 :     size_t p = 0;
     214             :     uint32_t len;
     215             :     uint32_t res;
     216             :     char *ccn;
     217             :     time_t expire_time;
     218             :     krb5_error_code krberr;
     219             : 
     220             :     /* operation result code */
     221           0 :     SAFEALIGN_COPY_UINT32_CHECK(&res, buf + p, size, &p);
     222             : 
     223             :     /* krb5 error code */
     224           0 :     safealign_memcpy(&krberr, buf+p, sizeof(krberr), &p);
     225             : 
     226             :     /* ccache name size */
     227           0 :     SAFEALIGN_COPY_UINT32_CHECK(&len, buf + p, size, &p);
     228             : 
     229           0 :     if (len > size - p) return EINVAL;
     230             : 
     231           0 :     ccn = talloc_size(mem_ctx, sizeof(char) * (len + 1));
     232           0 :     if (ccn == NULL) {
     233           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
     234           0 :         return ENOMEM;
     235             :     }
     236           0 :     safealign_memcpy(ccn, buf+p, sizeof(char) * len, &p);
     237           0 :     ccn[len] = '\0';
     238             : 
     239           0 :     if (p + sizeof(time_t) > size) {
     240           0 :         talloc_free(ccn);
     241           0 :         return EINVAL;
     242             :     }
     243           0 :     safealign_memcpy(&expire_time, buf+p, sizeof(time_t), &p);
     244             : 
     245           0 :     *result = res;
     246           0 :     *ccache = ccn;
     247           0 :     *expire_time_out = expire_time;
     248           0 :     *kerr = krberr;
     249           0 :     return EOK;
     250             : }
     251             : 
     252             : /* ==The-public-async-interface============================================*/
     253             : 
     254             : struct sdap_get_tgt_state {
     255             :     struct tevent_context *ev;
     256             :     struct sdap_child *child;
     257             :     ssize_t len;
     258             :     uint8_t *buf;
     259             : };
     260             : 
     261             : static errno_t set_tgt_child_timeout(struct tevent_req *req,
     262             :                                      struct tevent_context *ev,
     263             :                                      int timeout);
     264             : static void sdap_get_tgt_step(struct tevent_req *subreq);
     265             : static void sdap_get_tgt_done(struct tevent_req *subreq);
     266             : 
     267           0 : struct tevent_req *sdap_get_tgt_send(TALLOC_CTX *mem_ctx,
     268             :                                      struct tevent_context *ev,
     269             :                                      const char *realm_str,
     270             :                                      const char *princ_str,
     271             :                                      const char *keytab_name,
     272             :                                      int32_t lifetime,
     273             :                                      int timeout)
     274             : {
     275             :     struct tevent_req *req, *subreq;
     276             :     struct sdap_get_tgt_state *state;
     277             :     struct io_buffer *buf;
     278             :     int ret;
     279             : 
     280           0 :     req = tevent_req_create(mem_ctx, &state, struct sdap_get_tgt_state);
     281           0 :     if (!req) {
     282           0 :         return NULL;
     283             :     }
     284             : 
     285           0 :     state->ev = ev;
     286             : 
     287           0 :     state->child = talloc_zero(state, struct sdap_child);
     288           0 :     if (!state->child) {
     289           0 :         ret = ENOMEM;
     290           0 :         goto fail;
     291             :     }
     292             : 
     293           0 :     state->child->io = talloc(state, struct child_io_fds);
     294           0 :     if (state->child->io == NULL) {
     295           0 :         ret = ENOMEM;
     296           0 :         goto fail;
     297             :     }
     298           0 :     state->child->io->read_from_child_fd = -1;
     299           0 :     state->child->io->write_to_child_fd = -1;
     300           0 :     talloc_set_destructor((TALLOC_CTX *) state->child->io, child_io_destructor);
     301             : 
     302             :     /* prepare the data to pass to child */
     303           0 :     ret = create_tgt_req_send_buffer(state,
     304             :                                      realm_str, princ_str, keytab_name, lifetime,
     305             :                                      &buf);
     306           0 :     if (ret != EOK) {
     307           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "create_tgt_req_send_buffer failed.\n");
     308           0 :         goto fail;
     309             :     }
     310             : 
     311           0 :     ret = sdap_fork_child(state->ev, state->child);
     312           0 :     if (ret != EOK) {
     313           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sdap_fork_child failed.\n");
     314           0 :         goto fail;
     315             :     }
     316             : 
     317           0 :     ret = set_tgt_child_timeout(req, ev, timeout);
     318           0 :     if (ret != EOK) {
     319           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "activate_child_timeout_handler failed.\n");
     320           0 :         goto fail;
     321             :     }
     322             : 
     323           0 :     subreq = write_pipe_send(state, ev, buf->data, buf->size,
     324           0 :                              state->child->io->write_to_child_fd);
     325           0 :     if (!subreq) {
     326           0 :         ret = ENOMEM;
     327           0 :         goto fail;
     328             :     }
     329           0 :     tevent_req_set_callback(subreq, sdap_get_tgt_step, req);
     330             : 
     331           0 :     return req;
     332             : 
     333             : fail:
     334           0 :     tevent_req_error(req, ret);
     335           0 :     tevent_req_post(req, ev);
     336           0 :     return req;
     337             : }
     338             : 
     339           0 : static void sdap_get_tgt_step(struct tevent_req *subreq)
     340             : {
     341           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     342             :                                                       struct tevent_req);
     343           0 :     struct sdap_get_tgt_state *state = tevent_req_data(req,
     344             :                                                   struct sdap_get_tgt_state);
     345             :     int ret;
     346             : 
     347           0 :     ret = write_pipe_recv(subreq);
     348           0 :     talloc_zfree(subreq);
     349           0 :     if (ret != EOK) {
     350           0 :         tevent_req_error(req, ret);
     351           0 :         return;
     352             :     }
     353             : 
     354           0 :     sdap_close_fd(&state->child->io->write_to_child_fd);
     355             : 
     356           0 :     subreq = read_pipe_send(state, state->ev,
     357           0 :                             state->child->io->read_from_child_fd);
     358           0 :     if (!subreq) {
     359           0 :         tevent_req_error(req, ENOMEM);
     360           0 :         return;
     361             :     }
     362           0 :     tevent_req_set_callback(subreq, sdap_get_tgt_done, req);
     363             : }
     364             : 
     365           0 : static void sdap_get_tgt_done(struct tevent_req *subreq)
     366             : {
     367           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     368             :                                                       struct tevent_req);
     369           0 :     struct sdap_get_tgt_state *state = tevent_req_data(req,
     370             :                                                   struct sdap_get_tgt_state);
     371             :     int ret;
     372             : 
     373           0 :     ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
     374           0 :     talloc_zfree(subreq);
     375           0 :     if (ret != EOK) {
     376           0 :         tevent_req_error(req, ret);
     377           0 :         return;
     378             :     }
     379             : 
     380           0 :     sdap_close_fd(&state->child->io->read_from_child_fd);
     381             : 
     382           0 :     tevent_req_done(req);
     383             : }
     384             : 
     385           0 : int sdap_get_tgt_recv(struct tevent_req *req,
     386             :                       TALLOC_CTX *mem_ctx,
     387             :                       int  *result,
     388             :                       krb5_error_code *kerr,
     389             :                       char **ccname,
     390             :                       time_t *expire_time_out)
     391             : {
     392           0 :     struct sdap_get_tgt_state *state = tevent_req_data(req,
     393             :                                              struct sdap_get_tgt_state);
     394             :     char *ccn;
     395             :     time_t expire_time;
     396             :     int  res;
     397             :     int ret;
     398             :     krb5_error_code krberr;
     399             : 
     400           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     401             : 
     402           0 :     ret = parse_child_response(mem_ctx, state->buf, state->len,
     403             :                                &res, &krberr, &ccn, &expire_time);
     404           0 :     if (ret != EOK) {
     405           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     406             :               "Cannot parse child response: [%d][%s]\n", ret, strerror(ret));
     407           0 :         return ret;
     408             :     }
     409             : 
     410           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     411             :           "Child responded: %d [%s], expired on [%ld]\n", res, ccn, (long)expire_time);
     412           0 :     *result = res;
     413           0 :     *kerr = krberr;
     414           0 :     *ccname = ccn;
     415           0 :     *expire_time_out = expire_time;
     416           0 :     return EOK;
     417             : }
     418             : 
     419             : 
     420             : 
     421           0 : static void get_tgt_timeout_handler(struct tevent_context *ev,
     422             :                                     struct tevent_timer *te,
     423             :                                     struct timeval tv, void *pvt)
     424             : {
     425           0 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     426           0 :     struct sdap_get_tgt_state *state = tevent_req_data(req,
     427             :                                             struct sdap_get_tgt_state);
     428             :     int ret;
     429             : 
     430           0 :     DEBUG(SSSDBG_TRACE_ALL,
     431             :           "timeout for tgt child [%d] reached.\n", state->child->pid);
     432             : 
     433           0 :     ret = kill(state->child->pid, SIGKILL);
     434           0 :     if (ret == -1) {
     435           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     436             :               "kill failed [%d][%s].\n", errno, strerror(errno));
     437             :     }
     438             : 
     439           0 :     tevent_req_error(req, ETIMEDOUT);
     440           0 : }
     441             : 
     442           0 : static errno_t set_tgt_child_timeout(struct tevent_req *req,
     443             :                                      struct tevent_context *ev,
     444             :                                      int timeout)
     445             : {
     446             :     struct tevent_timer *te;
     447             :     struct timeval tv;
     448             : 
     449           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     450             :           "Setting %d seconds timeout for tgt child\n", timeout);
     451             : 
     452           0 :     tv = tevent_timeval_current_ofs(timeout, 0);
     453             : 
     454           0 :     te = tevent_add_timer(ev, req, tv, get_tgt_timeout_handler, req);
     455           0 :     if (te == NULL) {
     456           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
     457           0 :         return ENOMEM;
     458             :     }
     459             : 
     460           0 :     return EOK;
     461             : }
     462             : 
     463             : 
     464             : 
     465             : /* Setup child logging */
     466           0 : int sdap_setup_child(void)
     467             : {
     468           0 :     return child_debug_init(LDAP_CHILD_LOG_FILE, &ldap_child_debug_fd);
     469             : }

Generated by: LCOV version 1.10