LCOV - code coverage report
Current view: top level - responder/common - responder_common.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 100 458 21.8 %
Date: 2015-10-19 Functions: 6 22 27.3 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    Common Responder methods
       5             : 
       6             :    Copyright (C) Simo Sorce <ssorce@redhat.com>   2008
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : 
      24             : #include <stdio.h>
      25             : #include <sys/types.h>
      26             : #include <sys/stat.h>
      27             : #include <sys/socket.h>
      28             : #include <sys/un.h>
      29             : #include <string.h>
      30             : #include <sys/time.h>
      31             : #include <errno.h>
      32             : #include <popt.h>
      33             : #include <dbus/dbus.h>
      34             : 
      35             : #include "util/util.h"
      36             : #include "util/strtonum.h"
      37             : #include "db/sysdb.h"
      38             : #include "confdb/confdb.h"
      39             : #include "sbus/sssd_dbus.h"
      40             : #include "responder/common/responder.h"
      41             : #include "responder/common/responder_packet.h"
      42             : #include "providers/data_provider.h"
      43             : #include "monitor/monitor_interfaces.h"
      44             : #include "sbus/sbus_client.h"
      45             : 
      46           2 : static errno_t set_close_on_exec(int fd)
      47             : {
      48             :     int v;
      49             :     int ferr;
      50             :     errno_t error;
      51             : 
      52             :     /* Get the current flags for this file descriptor */
      53           2 :     v = fcntl(fd, F_GETFD, 0);
      54             : 
      55           2 :     errno = 0;
      56             :     /* Set the close-on-exec flags on this fd */
      57           2 :     ferr = fcntl(fd, F_SETFD, v | FD_CLOEXEC);
      58           2 :     if (ferr < 0) {
      59           0 :         error = errno;
      60           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
      61             :               "Unable to set fd close-on-exec: [%d][%s]\n",
      62             :                   error, strerror(error));
      63           0 :         return error;
      64             :     }
      65           2 :     return EOK;
      66             : }
      67             : 
      68           0 : static int client_destructor(struct cli_ctx *ctx)
      69             : {
      70             :     errno_t ret;
      71             : 
      72           0 :     if ((ctx->cfd > 0) && close(ctx->cfd) < 0) {
      73           0 :         ret = errno;
      74           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      75             :               "Failed to close fd [%d]: [%s]\n",
      76             :                ctx->cfd, strerror(ret));
      77             :     }
      78             : 
      79           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
      80             :           "Terminated client [%p][%d]\n",
      81             :            ctx, ctx->cfd);
      82           0 :     return 0;
      83             : }
      84             : 
      85           0 : static errno_t get_client_cred(struct cli_ctx *cctx)
      86             : {
      87           0 :     cctx->client_euid = -1;
      88           0 :     cctx->client_egid = -1;
      89           0 :     cctx->client_pid = -1;
      90             : 
      91             : #ifdef HAVE_UCRED
      92             :     int ret;
      93             :     struct ucred client_cred;
      94           0 :     socklen_t client_cred_len = sizeof(client_cred);
      95             : 
      96           0 :     ret = getsockopt(cctx->cfd, SOL_SOCKET, SO_PEERCRED, &client_cred,
      97             :                      &client_cred_len);
      98           0 :     if (ret != EOK) {
      99           0 :         ret = errno;
     100           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     101             :               "getsock failed [%d][%s].\n", ret, strerror(ret));
     102           0 :         return ret;
     103             :     }
     104           0 :     if (client_cred_len != sizeof(struct ucred)) {
     105           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     106             :               "getsockopt returned unexpected message size.\n");
     107           0 :         return ENOMSG;
     108             :     }
     109             : 
     110           0 :     cctx->client_euid = client_cred.uid;
     111           0 :     cctx->client_egid = client_cred.gid;
     112           0 :     cctx->client_pid = client_cred.pid;
     113             : 
     114           0 :     DEBUG(SSSDBG_TRACE_ALL, "Client creds: euid[%d] egid[%d] pid[%d].\n",
     115             :               cctx->client_euid, cctx->client_egid, cctx->client_pid);
     116             : #endif
     117             : 
     118           0 :     return EOK;
     119             : }
     120             : 
     121           8 : errno_t check_allowed_uids(uid_t uid, size_t allowed_uids_count,
     122             :                            uid_t *allowed_uids)
     123             : {
     124             :     size_t c;
     125             : 
     126           8 :     if (allowed_uids == NULL) {
     127           1 :         return EINVAL;
     128             :     }
     129             : 
     130          14 :     for (c = 0; c < allowed_uids_count; c++) {
     131          12 :         if (uid == allowed_uids[c]) {
     132           5 :             return EOK;
     133             :         }
     134             :     }
     135             : 
     136           2 :     return EACCES;
     137             : }
     138             : 
     139          15 : errno_t csv_string_to_uid_array(TALLOC_CTX *mem_ctx, const char *csv_string,
     140             :                                 bool allow_sss_loop,
     141             :                                 size_t *_uid_count, uid_t **_uids)
     142             : {
     143             :     int ret;
     144             :     size_t c;
     145          15 :     char **list = NULL;
     146             :     int list_size;
     147          15 :     uid_t *uids = NULL;
     148             :     char *endptr;
     149             : 
     150          15 :     ret = split_on_separator(mem_ctx, csv_string, ',', true, false,
     151             :                              &list, &list_size);
     152          15 :     if (ret != EOK) {
     153           2 :         DEBUG(SSSDBG_OP_FAILURE, "split_on_separator failed [%d][%s].\n",
     154             :                                   ret, strerror(ret));
     155           2 :         goto done;
     156             :     }
     157             : 
     158          13 :     uids = talloc_array(mem_ctx, uint32_t, list_size);
     159          13 :     if (uids == NULL) {
     160           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_array failed.\n");
     161           0 :         ret = ENOMEM;
     162           0 :         goto done;
     163             :     }
     164             : 
     165          13 :     if (allow_sss_loop) {
     166          12 :         ret = unsetenv("_SSS_LOOPS");
     167          12 :         if (ret != EOK) {
     168           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to unset _SSS_LOOPS, getpwnam "
     169             :                                       "might not find sssd users.\n");
     170             :         }
     171             :     }
     172             : 
     173          45 :     for (c = 0; c < list_size; c++) {
     174          37 :         errno = 0;
     175          37 :         if (*list[c] == '\0') {
     176           1 :             DEBUG(SSSDBG_OP_FAILURE, "Empty list item.\n");
     177           1 :             ret = EINVAL;
     178           1 :             goto done;
     179             :         }
     180             : 
     181          36 :         uids[c] = strtouint32(list[c], &endptr, 10);
     182          36 :         if (errno != 0 || *endptr != '\0') {
     183           7 :             ret = errno;
     184           7 :             if (ret == ERANGE) {
     185           2 :                 DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is out of range.\n",
     186             :                                           list[c]);
     187           2 :                 goto done;
     188             :             }
     189             : 
     190           5 :             ret = sss_user_by_name_or_uid(list[c], &uids[c], NULL);
     191           5 :             if (ret != EOK) {
     192           2 :                 DEBUG(SSSDBG_OP_FAILURE, "List item [%s] is neither a valid "
     193             :                                          "UID nor a user name which could be "
     194             :                                          "resolved by getpwnam().\n", list[c]);
     195           2 :                 sss_log(SSS_LOG_WARNING, "List item [%s] is neither a valid "
     196             :                                          "UID nor a user name which could be "
     197           2 :                                          "resolved by getpwnam().\n", list[c]);
     198           2 :                 goto done;
     199             :             }
     200             :         }
     201             :     }
     202             : 
     203           8 :     *_uid_count = list_size;
     204           8 :     *_uids = uids;
     205             : 
     206           8 :     ret = EOK;
     207             : 
     208             : done:
     209          15 :     if(setenv("_SSS_LOOPS", "NO", 0) != 0) {
     210           0 :         DEBUG(SSSDBG_OP_FAILURE, "Failed to set _SSS_LOOPS.\n");
     211             :     }
     212          15 :     talloc_free(list);
     213          15 :     if (ret != EOK) {
     214           7 :         talloc_free(uids);
     215             :     }
     216             : 
     217          15 :     return ret;
     218             : }
     219             : 
     220             : 
     221           0 : static void client_send(struct cli_ctx *cctx)
     222             : {
     223             :     int ret;
     224             : 
     225           0 :     ret = sss_packet_send(cctx->creq->out, cctx->cfd);
     226           0 :     if (ret == EAGAIN) {
     227             :         /* not all data was sent, loop again */
     228           0 :         return;
     229             :     }
     230           0 :     if (ret != EOK) {
     231           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to send data, aborting client!\n");
     232           0 :         talloc_free(cctx);
     233           0 :         return;
     234             :     }
     235             : 
     236             :     /* ok all sent */
     237           0 :     TEVENT_FD_NOT_WRITEABLE(cctx->cfde);
     238           0 :     TEVENT_FD_READABLE(cctx->cfde);
     239           0 :     talloc_free(cctx->creq);
     240           0 :     cctx->creq = NULL;
     241           0 :     return;
     242             : }
     243             : 
     244           0 : static int client_cmd_execute(struct cli_ctx *cctx, struct sss_cmd_table *sss_cmds)
     245             : {
     246             :     enum sss_cli_command cmd;
     247             : 
     248           0 :     cmd = sss_packet_get_cmd(cctx->creq->in);
     249           0 :     return sss_cmd_execute(cctx, cmd, sss_cmds);
     250             : }
     251             : 
     252           0 : static void client_recv(struct cli_ctx *cctx)
     253             : {
     254             :     int ret;
     255             : 
     256           0 :     if (!cctx->creq) {
     257           0 :         cctx->creq = talloc_zero(cctx, struct cli_request);
     258           0 :         if (!cctx->creq) {
     259           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     260             :                   "Failed to alloc request, aborting client!\n");
     261           0 :             talloc_free(cctx);
     262           0 :             return;
     263             :         }
     264             :     }
     265             : 
     266           0 :     if (!cctx->creq->in) {
     267           0 :         ret = sss_packet_new(cctx->creq, SSS_PACKET_MAX_RECV_SIZE,
     268           0 :                              0, &cctx->creq->in);
     269           0 :         if (ret != EOK) {
     270           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     271             :                   "Failed to alloc request, aborting client!\n");
     272           0 :             talloc_free(cctx);
     273           0 :             return;
     274             :         }
     275             :     }
     276             : 
     277           0 :     ret = sss_packet_recv(cctx->creq->in, cctx->cfd);
     278           0 :     switch (ret) {
     279             :     case EOK:
     280             :         /* do not read anymore */
     281           0 :         TEVENT_FD_NOT_READABLE(cctx->cfde);
     282             :         /* execute command */
     283           0 :         ret = client_cmd_execute(cctx, cctx->rctx->sss_cmds);
     284           0 :         if (ret != EOK) {
     285           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     286             :                   "Failed to execute request, aborting client!\n");
     287           0 :             talloc_free(cctx);
     288             :         }
     289             :         /* past this point cctx can be freed at any time by callbacks
     290             :          * in case of error, do not use it */
     291           0 :         return;
     292             : 
     293             :     case EAGAIN:
     294             :         /* need to read still some data, loop again */
     295           0 :         break;
     296             : 
     297             :     case EINVAL:
     298           0 :         DEBUG(SSSDBG_TRACE_FUNC,
     299             :               "Invalid data from client, closing connection!\n");
     300           0 :         talloc_free(cctx);
     301           0 :         break;
     302             : 
     303             :     case ENODATA:
     304           0 :         DEBUG(SSSDBG_FUNC_DATA, "Client disconnected!\n");
     305           0 :         talloc_free(cctx);
     306           0 :         break;
     307             : 
     308             :     default:
     309           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Failed to read request, aborting client!\n");
     310           0 :         talloc_free(cctx);
     311             :     }
     312             : 
     313           0 :     return;
     314             : }
     315             : 
     316             : static errno_t reset_idle_timer(struct cli_ctx *cctx);
     317             : 
     318           0 : static void client_fd_handler(struct tevent_context *ev,
     319             :                               struct tevent_fd *fde,
     320             :                               uint16_t flags, void *ptr)
     321             : {
     322             :     errno_t ret;
     323           0 :     struct cli_ctx *cctx = talloc_get_type(ptr, struct cli_ctx);
     324             : 
     325             :     /* Always reset the idle timer on any activity */
     326           0 :     ret = reset_idle_timer(cctx);
     327           0 :     if (ret != EOK) {
     328           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     329             :               "Could not create idle timer for client. "
     330             :                "This connection may not auto-terminate\n");
     331             :         /* Non-fatal, continue */
     332             :     }
     333             : 
     334           0 :     if (flags & TEVENT_FD_READ) {
     335           0 :         client_recv(cctx);
     336           0 :         return;
     337             :     }
     338           0 :     if (flags & TEVENT_FD_WRITE) {
     339           0 :         client_send(cctx);
     340           0 :         return;
     341             :     }
     342             : }
     343             : 
     344             : struct accept_fd_ctx {
     345             :     struct resp_ctx *rctx;
     346             :     bool is_private;
     347             : };
     348             : 
     349             : static void idle_handler(struct tevent_context *ev,
     350             :                          struct tevent_timer *te,
     351             :                          struct timeval current_time,
     352             :                          void *data);
     353             : 
     354           0 : static void accept_fd_handler(struct tevent_context *ev,
     355             :                               struct tevent_fd *fde,
     356             :                               uint16_t flags, void *ptr)
     357             : {
     358             :     /* accept and attach new event handler */
     359           0 :     struct accept_fd_ctx *accept_ctx =
     360             :             talloc_get_type(ptr, struct accept_fd_ctx);
     361           0 :     struct resp_ctx *rctx = accept_ctx->rctx;
     362             :     struct cli_ctx *cctx;
     363             :     socklen_t len;
     364             :     struct stat stat_buf;
     365             :     int ret;
     366           0 :     int fd = accept_ctx->is_private ? rctx->priv_lfd : rctx->lfd;
     367             :     int client_fd;
     368             : 
     369           0 :     if (accept_ctx->is_private) {
     370           0 :         ret = stat(rctx->priv_sock_name, &stat_buf);
     371           0 :         if (ret == -1) {
     372           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     373             :                   "stat on privileged pipe failed: [%d][%s].\n", errno,
     374             :                       strerror(errno));
     375           0 :             return;
     376             :         }
     377             : 
     378           0 :         if ( ! (stat_buf.st_uid == 0 && stat_buf.st_gid == 0 &&
     379           0 :                (stat_buf.st_mode&(S_IFSOCK|S_IRUSR|S_IWUSR)) == stat_buf.st_mode)) {
     380           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     381             :                   "privileged pipe has an illegal status.\n");
     382             :     /* TODO: what is the best response to this condition? Terminate? */
     383           0 :             return;
     384             :         }
     385             :     }
     386             : 
     387           0 :     cctx = talloc_zero(rctx, struct cli_ctx);
     388           0 :     if (!cctx) {
     389             :         struct sockaddr_un addr;
     390           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     391             :               "Out of memory trying to setup client context%s!\n",
     392             :                   accept_ctx->is_private ? " on privileged pipe": "");
     393             :         /* accept and close to signal the client we have a problem */
     394           0 :         memset(&addr, 0, sizeof(addr));
     395           0 :         len = sizeof(addr);
     396           0 :         client_fd = accept(fd, (struct sockaddr *)&addr, &len);
     397           0 :         if (client_fd == -1) {
     398           0 :             return;
     399             :         }
     400           0 :         close(client_fd);
     401           0 :         return;
     402             :     }
     403             : 
     404           0 :     len = sizeof(cctx->addr);
     405           0 :     cctx->cfd = accept(fd, (struct sockaddr *)&cctx->addr, &len);
     406           0 :     if (cctx->cfd == -1) {
     407           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Accept failed [%s]\n", strerror(errno));
     408           0 :         talloc_free(cctx);
     409           0 :         return;
     410             :     }
     411             : 
     412           0 :     cctx->priv = accept_ctx->is_private;
     413             : 
     414           0 :     ret = get_client_cred(cctx);
     415           0 :     if (ret != EOK) {
     416           0 :         DEBUG(SSSDBG_OP_FAILURE, "get_client_cred failed, "
     417             :                   "client cred may not be available.\n");
     418             :     }
     419             : 
     420           0 :     if (rctx->allowed_uids_count != 0) {
     421           0 :         if (cctx->client_euid == -1) {
     422           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "allowed_uids configured, " \
     423             :                                         "but platform does not support " \
     424             :                                         "reading peer credential from the " \
     425             :                                         "socket. Access denied.\n");
     426           0 :             close(cctx->cfd);
     427           0 :             talloc_free(cctx);
     428           0 :             return;
     429             :         }
     430             : 
     431           0 :         ret = check_allowed_uids(cctx->client_euid, rctx->allowed_uids_count,
     432             :                                  rctx->allowed_uids);
     433           0 :         if (ret != EOK) {
     434           0 :             if (ret == EACCES) {
     435           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Access denied for uid [%d].\n",
     436             :                                             cctx->client_euid);
     437             :             } else {
     438           0 :                 DEBUG(SSSDBG_OP_FAILURE, "check_allowed_uids failed.\n");
     439             :             }
     440           0 :             close(cctx->cfd);
     441           0 :             talloc_free(cctx);
     442           0 :             return;
     443             :         }
     444             :     }
     445             : 
     446           0 :     cctx->cfde = tevent_add_fd(ev, cctx, cctx->cfd,
     447             :                                TEVENT_FD_READ, client_fd_handler, cctx);
     448           0 :     if (!cctx->cfde) {
     449           0 :         close(cctx->cfd);
     450           0 :         talloc_free(cctx);
     451           0 :         DEBUG(SSSDBG_OP_FAILURE,
     452             :               "Failed to queue client handler%s\n",
     453             :                accept_ctx->is_private ? " on privileged pipe" : "");
     454           0 :         return;
     455             :     }
     456             : 
     457           0 :     cctx->ev = ev;
     458           0 :     cctx->rctx = rctx;
     459             : 
     460           0 :     talloc_set_destructor(cctx, client_destructor);
     461             : 
     462             :     /* Set up the idle timer */
     463           0 :     ret = reset_idle_timer(cctx);
     464           0 :     if (ret != EOK) {
     465           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     466             :               "Could not create idle timer for client. "
     467             :                "This connection may not auto-terminate\n");
     468             :         /* Non-fatal, continue */
     469             :     }
     470             : 
     471           0 :     DEBUG(SSSDBG_TRACE_FUNC,
     472             :           "Client connected%s!\n",
     473             :            accept_ctx->is_private ? " to privileged pipe" : "");
     474             : 
     475           0 :     return;
     476             : }
     477             : 
     478           0 : static errno_t reset_idle_timer(struct cli_ctx *cctx)
     479             : {
     480           0 :     struct timeval tv =
     481           0 :             tevent_timeval_current_ofs(cctx->rctx->client_idle_timeout, 0);
     482             : 
     483           0 :     talloc_zfree(cctx->idle);
     484             : 
     485           0 :     cctx->idle = tevent_add_timer(cctx->ev, cctx, tv, idle_handler, cctx);
     486           0 :     if (!cctx->idle) return ENOMEM;
     487             : 
     488           0 :     DEBUG(SSSDBG_TRACE_ALL,
     489             :           "Idle timer re-set for client [%p][%d]\n",
     490             :            cctx, cctx->cfd);
     491             : 
     492           0 :     return EOK;
     493             : }
     494             : 
     495           0 : static void idle_handler(struct tevent_context *ev,
     496             :                          struct tevent_timer *te,
     497             :                          struct timeval current_time,
     498             :                          void *data)
     499             : {
     500             :     /* This connection is idle. Terminate it */
     501           0 :     struct cli_ctx *cctx =
     502             :             talloc_get_type(data, struct cli_ctx);
     503             : 
     504           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     505             :           "Terminating idle client [%p][%d]\n",
     506             :            cctx, cctx->cfd);
     507             : 
     508             :     /* The cli_ctx destructor will handle the rest */
     509           0 :     talloc_free(cctx);
     510           0 : }
     511             : 
     512           0 : static int sss_dp_init(struct resp_ctx *rctx,
     513             :                        struct sbus_vtable *dp_intf,
     514             :                        const char *cli_name,
     515             :                        struct sss_domain_info *domain)
     516             : {
     517             :     struct be_conn *be_conn;
     518             :     int ret;
     519             : 
     520           0 :     be_conn = talloc_zero(rctx, struct be_conn);
     521           0 :     if (!be_conn) return ENOMEM;
     522             : 
     523           0 :     be_conn->cli_name = cli_name;
     524           0 :     be_conn->domain = domain;
     525           0 :     be_conn->rctx = rctx;
     526             : 
     527             :     /* Set up SBUS connection to the monitor */
     528           0 :     ret = dp_get_sbus_address(be_conn, &be_conn->sbus_address, domain->name);
     529           0 :     if (ret != EOK) {
     530           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Could not locate DP address.\n");
     531           0 :         return ret;
     532             :     }
     533           0 :     ret = sbus_client_init(rctx, rctx->ev,
     534           0 :                            be_conn->sbus_address,
     535             :                            &be_conn->conn);
     536           0 :     if (ret != EOK) {
     537           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to connect to monitor services.\n");
     538           0 :         return ret;
     539             :     }
     540             : 
     541           0 :     ret = sbus_conn_register_iface(be_conn->conn, dp_intf, DP_PATH, rctx);
     542           0 :     if (ret != EOK) {
     543           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to export data provider.\n");
     544           0 :         return ret;
     545             :     }
     546             : 
     547           0 :     DLIST_ADD_END(rctx->be_conns, be_conn, struct be_conn *);
     548             : 
     549             :     /* Identify ourselves to the DP */
     550           0 :     ret = dp_common_send_id(be_conn->conn,
     551             :                             DATA_PROVIDER_VERSION,
     552             :                             cli_name);
     553           0 :     if (ret != EOK) {
     554           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "Failed to identify to the DP!\n");
     555           0 :         return ret;
     556             :     }
     557             : 
     558           0 :     return EOK;
     559             : }
     560             : 
     561           2 : int create_pipe_fd(const char *sock_name, int *_fd, mode_t umaskval)
     562             : {
     563             :     struct sockaddr_un addr;
     564             :     mode_t orig_umaskval;
     565             :     errno_t ret;
     566             :     int fd;
     567             : 
     568           2 :     fd = socket(AF_UNIX, SOCK_STREAM, 0);
     569           2 :     if (fd == -1) {
     570           0 :         return EIO;
     571             :     }
     572             : 
     573           2 :     orig_umaskval = umask(umaskval);
     574             : 
     575           2 :     ret = sss_fd_nonblocking(fd);
     576           2 :     if (ret != EOK) {
     577           0 :         goto done;
     578             :     }
     579             : 
     580           2 :     ret = set_close_on_exec(fd);
     581           2 :     if (ret != EOK) {
     582           0 :         goto done;
     583             :     }
     584             : 
     585           2 :     memset(&addr, 0, sizeof(addr));
     586           2 :     addr.sun_family = AF_UNIX;
     587           2 :     strncpy(addr.sun_path, sock_name, sizeof(addr.sun_path) - 1);
     588           2 :     addr.sun_path[sizeof(addr.sun_path) - 1] = '\0';
     589             : 
     590             :     /* make sure we have no old sockets around */
     591           2 :     ret = unlink(sock_name);
     592           2 :     if (ret != 0 && errno != ENOENT) {
     593           0 :         ret = errno;
     594           0 :         DEBUG(SSSDBG_MINOR_FAILURE,
     595             :               "Cannot remove old socket (errno=%d), bind might fail!\n", ret);
     596             :     }
     597             : 
     598           2 :     if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
     599           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     600             :               "Unable to bind on socket '%s'\n", sock_name);
     601           0 :         ret = EIO;
     602           0 :         goto done;
     603             :     }
     604           2 :     if (listen(fd, 10) == -1) {
     605           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     606             :               "Unable to listen on socket '%s'\n", sock_name);
     607           0 :         ret = EIO;
     608           0 :         goto done;
     609             :     }
     610             : 
     611           2 :     ret = EOK;
     612             : 
     613             : done:
     614             :     /* restore previous umask value */
     615           2 :     umask(orig_umaskval);
     616           2 :     if (ret == EOK) {
     617           2 :         *_fd = fd;
     618             :     } else {
     619           0 :         close(fd);
     620             :     }
     621           2 :     return ret;
     622             : }
     623             : 
     624             : /* create a unix socket and listen to it */
     625           0 : static int set_unix_socket(struct resp_ctx *rctx)
     626             : {
     627             :     errno_t ret;
     628             :     struct accept_fd_ctx *accept_ctx;
     629             : 
     630             : /* for future use */
     631             : #if 0
     632             :     char *default_pipe;
     633             :     int ret;
     634             : 
     635             :     default_pipe = talloc_asprintf(rctx, "%s/%s", PIPE_PATH,
     636             :                                    rctx->sss_pipe_name);
     637             :     if (!default_pipe) {
     638             :         return ENOMEM;
     639             :     }
     640             : 
     641             :     ret = confdb_get_string(rctx->cdb, rctx,
     642             :                             rctx->confdb_socket_path, "unixSocket",
     643             :                             default_pipe, &rctx->sock_name);
     644             :     if (ret != EOK) {
     645             :         talloc_free(default_pipe);
     646             :         return ret;
     647             :     }
     648             :     talloc_free(default_pipe);
     649             : 
     650             :     default_pipe = talloc_asprintf(rctx, "%s/private/%s", PIPE_PATH,
     651             :                                    rctx->sss_pipe_name);
     652             :     if (!default_pipe) {
     653             :         return ENOMEM;
     654             :     }
     655             : 
     656             :     ret = confdb_get_string(rctx->cdb, rctx,
     657             :                             rctx->confdb_socket_path, "privUnixSocket",
     658             :                             default_pipe, &rctx->priv_sock_name);
     659             :     if (ret != EOK) {
     660             :         talloc_free(default_pipe);
     661             :         return ret;
     662             :     }
     663             :     talloc_free(default_pipe);
     664             : #endif
     665             : 
     666           0 :     if (rctx->sock_name != NULL ) {
     667             :         /* Set the umask so that permissions are set right on the socket.
     668             :          * It must be readable and writable by anybody on the system. */
     669           0 :         if (rctx->lfd == -1) {
     670           0 :             ret = create_pipe_fd(rctx->sock_name, &rctx->lfd, SCKT_RSP_UMASK);
     671           0 :             if (ret != EOK) {
     672           0 :                 return ret;
     673             :             }
     674             :         }
     675             : 
     676           0 :         accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
     677           0 :         if(!accept_ctx) goto failed;
     678           0 :         accept_ctx->rctx = rctx;
     679           0 :         accept_ctx->is_private = false;
     680             : 
     681           0 :         rctx->lfde = tevent_add_fd(rctx->ev, rctx, rctx->lfd,
     682             :                                    TEVENT_FD_READ, accept_fd_handler,
     683             :                                    accept_ctx);
     684           0 :         if (!rctx->lfde) {
     685           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Failed to queue handler on pipe\n");
     686           0 :             goto failed;
     687             :         }
     688             :     }
     689             : 
     690           0 :     if (rctx->priv_sock_name != NULL ) {
     691             :         /* create privileged pipe */
     692           0 :         if (rctx->priv_lfd == -1) {
     693           0 :             ret = create_pipe_fd(rctx->priv_sock_name, &rctx->priv_lfd,
     694             :                                  DFL_RSP_UMASK);
     695           0 :             if (ret != EOK) {
     696           0 :                 goto failed;
     697             :             }
     698             :         }
     699             : 
     700           0 :         accept_ctx = talloc_zero(rctx, struct accept_fd_ctx);
     701           0 :         if(!accept_ctx) goto failed;
     702           0 :         accept_ctx->rctx = rctx;
     703           0 :         accept_ctx->is_private = true;
     704             : 
     705           0 :         rctx->priv_lfde = tevent_add_fd(rctx->ev, rctx, rctx->priv_lfd,
     706             :                                    TEVENT_FD_READ, accept_fd_handler,
     707             :                                    accept_ctx);
     708           0 :         if (!rctx->priv_lfde) {
     709           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     710             :                   "Failed to queue handler on privileged pipe\n");
     711           0 :             goto failed;
     712             :         }
     713             :     }
     714             : 
     715           0 :     return EOK;
     716             : 
     717             : failed:
     718           0 :     close(rctx->lfd);
     719           0 :     close(rctx->priv_lfd);
     720           0 :     return EIO;
     721             : }
     722             : 
     723           0 : static int sss_responder_ctx_destructor(void *ptr)
     724             : {
     725           0 :     struct resp_ctx *rctx = talloc_get_type(ptr, struct resp_ctx);
     726             : 
     727             :     /* mark that we are shutting down the responder, so it is propagated
     728             :      * into underlying contexts that are freed right before rctx */
     729           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Responder is being shut down\n");
     730           0 :     rctx->shutting_down = true;
     731             : 
     732           0 :     return 0;
     733             : }
     734             : 
     735           0 : int sss_process_init(TALLOC_CTX *mem_ctx,
     736             :                      struct tevent_context *ev,
     737             :                      struct confdb_ctx *cdb,
     738             :                      struct sss_cmd_table sss_cmds[],
     739             :                      const char *sss_pipe_name,
     740             :                      int pipe_fd,
     741             :                      const char *sss_priv_pipe_name,
     742             :                      int priv_pipe_fd,
     743             :                      const char *confdb_service_path,
     744             :                      const char *svc_name,
     745             :                      uint16_t svc_version,
     746             :                      struct mon_cli_iface *monitor_intf,
     747             :                      const char *cli_name,
     748             :                      struct sbus_vtable *dp_intf,
     749             :                      struct resp_ctx **responder_ctx)
     750             : {
     751             :     struct resp_ctx *rctx;
     752             :     struct sss_domain_info *dom;
     753             :     int ret;
     754           0 :     char *tmp = NULL;
     755             : 
     756           0 :     rctx = talloc_zero(mem_ctx, struct resp_ctx);
     757           0 :     if (!rctx) {
     758           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n");
     759           0 :         return ENOMEM;
     760             :     }
     761           0 :     rctx->ev = ev;
     762           0 :     rctx->cdb = cdb;
     763           0 :     rctx->sss_cmds = sss_cmds;
     764           0 :     rctx->sock_name = sss_pipe_name;
     765           0 :     rctx->priv_sock_name = sss_priv_pipe_name;
     766           0 :     rctx->lfd = pipe_fd;
     767           0 :     rctx->priv_lfd = priv_pipe_fd;
     768           0 :     rctx->confdb_service_path = confdb_service_path;
     769           0 :     rctx->shutting_down = false;
     770             : 
     771           0 :     talloc_set_destructor((TALLOC_CTX*)rctx, sss_responder_ctx_destructor);
     772             : 
     773           0 :     ret = confdb_get_int(rctx->cdb, rctx->confdb_service_path,
     774             :                          CONFDB_RESPONDER_CLI_IDLE_TIMEOUT,
     775             :                          CONFDB_RESPONDER_CLI_IDLE_DEFAULT_TIMEOUT,
     776             :                          &rctx->client_idle_timeout);
     777           0 :     if (ret != EOK) {
     778           0 :         DEBUG(SSSDBG_OP_FAILURE,
     779             :               "Cannot get the client idle timeout [%d]: %s\n",
     780             :                ret, strerror(ret));
     781           0 :         goto fail;
     782             :     }
     783             : 
     784             :     /* Ensure that the client timeout is at least ten seconds */
     785           0 :     if (rctx->client_idle_timeout < 10) {
     786           0 :         rctx->client_idle_timeout = 10;
     787             :     }
     788             : 
     789           0 :     ret = confdb_get_int(rctx->cdb, rctx->confdb_service_path,
     790             :                          CONFDB_RESPONDER_GET_DOMAINS_TIMEOUT,
     791             :                          GET_DOMAINS_DEFAULT_TIMEOUT, &rctx->domains_timeout);
     792           0 :     if (ret != EOK) {
     793           0 :         DEBUG(SSSDBG_OP_FAILURE,
     794             :               "Cannnot get the default domain timeout [%d]: %s\n",
     795             :                ret, strerror(ret));
     796           0 :         goto fail;
     797             :     }
     798             : 
     799           0 :     if (rctx->domains_timeout < 0) {
     800           0 :         DEBUG(SSSDBG_CONF_SETTINGS, "timeout can't be set to negative value, setting default\n");
     801           0 :         rctx->domains_timeout = GET_DOMAINS_DEFAULT_TIMEOUT;
     802             :     }
     803             : 
     804           0 :     ret = confdb_get_domains(rctx->cdb, &rctx->domains);
     805           0 :     if (ret != EOK) {
     806           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up domain map\n");
     807           0 :         goto fail;
     808             :     }
     809             : 
     810           0 :     ret = confdb_get_string(rctx->cdb, rctx, CONFDB_MONITOR_CONF_ENTRY,
     811             :                             CONFDB_MONITOR_DEFAULT_DOMAIN, NULL,
     812             :                             &rctx->default_domain);
     813           0 :     if (ret != EOK) {
     814           0 :         DEBUG(SSSDBG_OP_FAILURE,
     815             :               "Cannnot get the default domain [%d]: %s\n",
     816             :                ret, strerror(ret));
     817           0 :         goto fail;
     818             :     }
     819             : 
     820           0 :     ret = confdb_get_string(rctx->cdb, rctx, CONFDB_MONITOR_CONF_ENTRY,
     821             :                             CONFDB_MONITOR_OVERRIDE_SPACE, NULL,
     822             :                             &tmp);
     823           0 :     if (ret != EOK) {
     824           0 :         DEBUG(SSSDBG_OP_FAILURE,
     825             :               "Cannnot get the space substitution character [%d]: %s\n",
     826             :                ret, strerror(ret));
     827           0 :         goto fail;
     828             :     }
     829             : 
     830           0 :     if (tmp != NULL) {
     831           0 :         if (strlen(tmp) > 1) {
     832           0 :             DEBUG(SSSDBG_MINOR_FAILURE, "Option %s is longer than 1 character "
     833             :                   "only the first character %c will be used\n",
     834             :                   CONFDB_MONITOR_OVERRIDE_SPACE, tmp[0]);
     835             :         }
     836             : 
     837           0 :         rctx->override_space = tmp[0];
     838             :     }
     839             : 
     840           0 :     ret = sss_monitor_init(rctx, rctx->ev, monitor_intf,
     841             :                            svc_name, svc_version, rctx,
     842             :                            &rctx->mon_conn);
     843           0 :     if (ret != EOK) {
     844           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error setting up message bus\n");
     845           0 :         goto fail;
     846             :     }
     847             : 
     848           0 :     for (dom = rctx->domains; dom; dom = get_next_domain(dom, false)) {
     849           0 :         ret = sss_names_init(rctx->cdb, rctx->cdb, dom->name, &dom->names);
     850           0 :         if (ret != EOK) {
     851           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     852             :                   "fatal error initializing regex data for domain: %s\n",
     853             :                    dom->name);
     854           0 :             goto fail;
     855             :         }
     856             : 
     857             :         /* skip local domain, it doesn't have a backend */
     858           0 :         if (strcasecmp(dom->provider, "local") == 0) {
     859           0 :             continue;
     860             :         }
     861             : 
     862           0 :         ret = sss_dp_init(rctx, dp_intf, cli_name, dom);
     863           0 :         if (ret != EOK) {
     864           0 :             DEBUG(SSSDBG_FATAL_FAILURE,
     865             :                   "fatal error setting up backend connector\n");
     866           0 :             goto fail;
     867             :         }
     868             :     }
     869             : 
     870           0 :     ret = sysdb_init(rctx, rctx->domains, false);
     871           0 :     if (ret != EOK) {
     872           0 :         SYSDB_VERSION_ERROR_DAEMON(ret);
     873           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing resp_ctx\n");
     874           0 :         goto fail;
     875             :     }
     876             : 
     877             :     /* after all initializations we are ready to listen on our socket */
     878           0 :     ret = set_unix_socket(rctx);
     879           0 :     if (ret != EOK) {
     880           0 :         DEBUG(SSSDBG_FATAL_FAILURE, "fatal error initializing socket\n");
     881           0 :         goto fail;
     882             :     }
     883             : 
     884             :     /* Create DP request table */
     885           0 :     ret = sss_hash_create(rctx, 30, &rctx->dp_request_table);
     886           0 :     if (ret != EOK) {
     887           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     888             :               "Could not create hash table for the request queue\n");
     889           0 :         goto fail;
     890             :     }
     891             : 
     892           0 :     DEBUG(SSSDBG_TRACE_FUNC, "Responder Initialization complete\n");
     893             : 
     894           0 :     *responder_ctx = rctx;
     895           0 :     return EOK;
     896             : 
     897             : fail:
     898           0 :     talloc_free(rctx);
     899           0 :     return ret;
     900             : }
     901             : 
     902           0 : int sss_dp_get_domain_conn(struct resp_ctx *rctx, const char *domain,
     903             :                            struct be_conn **_conn)
     904             : {
     905             :     struct be_conn *iter;
     906             : 
     907           0 :     if (!rctx->be_conns) return ENOENT;
     908             : 
     909           0 :     for (iter = rctx->be_conns; iter; iter = iter->next) {
     910           0 :         if (strcasecmp(domain, iter->domain->name) == 0) break;
     911             :     }
     912             : 
     913           0 :     if (!iter) return ENOENT;
     914             : 
     915           0 :     *_conn = iter;
     916             : 
     917           0 :     return EOK;
     918             : }
     919             : 
     920             : struct sss_domain_info *
     921          55 : responder_get_domain(struct resp_ctx *rctx, const char *name)
     922             : {
     923             :     struct sss_domain_info *dom;
     924          55 :     struct sss_domain_info *ret_dom = NULL;
     925             : 
     926          77 :     for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
     927          71 :         if (sss_domain_get_state(dom) == DOM_DISABLED) {
     928           0 :             continue;
     929             :         }
     930             : 
     931          93 :         if (strcasecmp(dom->name, name) == 0 ||
     932          22 :             (dom->flat_name != NULL &&
     933           0 :              strcasecmp(dom->flat_name, name) == 0)) {
     934          49 :             ret_dom = dom;
     935          49 :             break;
     936             :         }
     937             :     }
     938             : 
     939          55 :     if (!ret_dom) {
     940           6 :         DEBUG(SSSDBG_OP_FAILURE, "Unknown domain [%s]\n", name);
     941             :     }
     942             : 
     943          55 :     return ret_dom;
     944             : }
     945             : 
     946           4 : errno_t responder_get_domain_by_id(struct resp_ctx *rctx, const char *id,
     947             :                                    struct sss_domain_info **_ret_dom)
     948             : {
     949             :     struct sss_domain_info *dom;
     950           4 :     struct sss_domain_info *ret_dom = NULL;
     951             :     size_t id_len;
     952             :     size_t dom_id_len;
     953             :     int ret;
     954             : 
     955           4 :     if (id == NULL || _ret_dom == NULL) {
     956           0 :         return EINVAL;
     957             :     }
     958             : 
     959           4 :     id_len = strlen(id);
     960             : 
     961           4 :     for (dom = rctx->domains; dom; dom = get_next_domain(dom, true)) {
     962           8 :         if (sss_domain_get_state(dom) == DOM_DISABLED ||
     963           4 :                 dom->domain_id == NULL) {
     964           0 :             continue;
     965             :         }
     966             : 
     967           4 :         dom_id_len = strlen(dom->domain_id);
     968           8 :         if ((id_len >= dom_id_len) &&
     969           4 :             strncasecmp(dom->domain_id, id, dom_id_len) == 0) {
     970           4 :             if (IS_SUBDOMAIN(dom) &&
     971           0 :                 ((time(NULL) - dom->parent->subdomains_last_checked.tv_sec) >
     972           0 :                                                       rctx->domains_timeout)) {
     973           0 :                 DEBUG(SSSDBG_TRACE_FUNC, "Domain entry with id [%s] " \
     974             :                                           "is expired.\n", id);
     975           0 :                 ret = EAGAIN;
     976           0 :                 goto done;
     977             :             }
     978           4 :             ret_dom = dom;
     979           4 :             break;
     980             :         }
     981             :     }
     982             : 
     983           4 :     if (ret_dom == NULL) {
     984           0 :         DEBUG(SSSDBG_OP_FAILURE, "Unknown domain id [%s], checking for "
     985             :                                   "possible subdomains!\n", id);
     986           0 :         ret = ENOENT;
     987             :     } else {
     988           4 :         *_ret_dom = ret_dom;
     989           4 :         ret = EOK;
     990             :     }
     991             : 
     992             : done:
     993           4 :     return ret;
     994             : }
     995             : 
     996           0 : int responder_logrotate(struct sbus_request *dbus_req, void *data)
     997             : {
     998             :     errno_t ret;
     999           0 :     struct resp_ctx *rctx = talloc_get_type(data, struct resp_ctx);
    1000             : 
    1001           0 :     ret = server_common_rotate_logs(rctx->cdb, rctx->confdb_service_path);
    1002           0 :     if (ret != EOK) return ret;
    1003             : 
    1004           0 :     return sbus_request_return_and_finish(dbus_req, DBUS_TYPE_INVALID);
    1005             : }
    1006             : 
    1007           0 : void responder_set_fd_limit(rlim_t fd_limit)
    1008             : {
    1009             :     struct rlimit current_limit, new_limit;
    1010             :     int limret;
    1011             : 
    1012             :     /* First, let's see if we have permission to just set
    1013             :      * the value as-is.
    1014             :      */
    1015           0 :     new_limit.rlim_cur = fd_limit;
    1016           0 :     new_limit.rlim_max = fd_limit;
    1017           0 :     limret = setrlimit(RLIMIT_NOFILE, &new_limit);
    1018           0 :     if (limret == 0) {
    1019           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
    1020             :               "Maximum file descriptors set to [%"SPRIrlim"]\n",
    1021             :                new_limit.rlim_cur);
    1022           0 :         return;
    1023             :     }
    1024             : 
    1025             :     /* We couldn't set the soft and hard limits to this
    1026             :      * value. Let's see how high we CAN set it.
    1027             :      */
    1028             : 
    1029             :     /* Determine the maximum hard limit */
    1030           0 :     limret = getrlimit(RLIMIT_NOFILE, &current_limit);
    1031           0 :     if (limret == 0) {
    1032           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
    1033             :               "Current fd limit: [%"SPRIrlim"]\n",
    1034             :                current_limit.rlim_cur);
    1035             :         /* Choose the lesser of the requested and the hard limit */
    1036           0 :         if (current_limit.rlim_max < fd_limit) {
    1037           0 :             new_limit.rlim_cur = current_limit.rlim_max;
    1038             :         } else {
    1039           0 :             new_limit.rlim_cur = fd_limit;
    1040             :         }
    1041           0 :         new_limit.rlim_max = current_limit.rlim_max;
    1042             : 
    1043           0 :         limret = setrlimit(RLIMIT_NOFILE, &new_limit);
    1044           0 :         if (limret == 0) {
    1045           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
    1046             :                   "Maximum file descriptors set to [%"SPRIrlim"]\n",
    1047             :                    new_limit.rlim_cur);
    1048             :         } else {
    1049           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
    1050             :                   "Could not set new fd limits. Proceeding with "
    1051             :                    "[%"SPRIrlim"]\n", current_limit.rlim_cur);
    1052             :         }
    1053             :     } else {
    1054           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
    1055             :               "Could not determine fd limits. "
    1056             :                "Proceeding with system values\n");
    1057             :     }
    1058             : }

Generated by: LCOV version 1.10