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

Generated by: LCOV version 1.10