LCOV - code coverage report
Current view: top level - providers/proxy - proxy_auth.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 347 0.0 %
Date: 2015-10-19 Functions: 0 18 0.0 %

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     proxy_auth.c
       5             : 
       6             :     Authors:
       7             :         Stephen Gallagher <sgallagh@redhat.com>
       8             : 
       9             :     Copyright (C) 2010 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 "providers/proxy/proxy.h"
      26             : 
      27             : struct proxy_client_ctx {
      28             :     struct be_req *be_req;
      29             :     struct proxy_auth_ctx *auth_ctx;
      30             : };
      31             : 
      32             : static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
      33             :                                            struct proxy_auth_ctx *ctx,
      34             :                                            struct be_req *be_req);
      35             : static void proxy_child_done(struct tevent_req *child_req);
      36           0 : void proxy_pam_handler(struct be_req *req)
      37             : {
      38           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(req);
      39             :     struct pam_data *pd;
      40             :     struct proxy_auth_ctx *ctx;
      41           0 :     struct tevent_req *child_req = NULL;
      42             :     struct proxy_client_ctx *client_ctx;
      43             : 
      44           0 :     pd = talloc_get_type(be_req_get_data(req), struct pam_data);
      45             : 
      46           0 :     switch (pd->cmd) {
      47             :         case SSS_PAM_AUTHENTICATE:
      48           0 :             ctx = talloc_get_type(be_ctx->bet_info[BET_AUTH].pvt_bet_data,
      49             :                                   struct proxy_auth_ctx);
      50           0 :             break;
      51             :         case SSS_PAM_CHAUTHTOK:
      52             :         case SSS_PAM_CHAUTHTOK_PRELIM:
      53           0 :             ctx = talloc_get_type(be_ctx->bet_info[BET_CHPASS].pvt_bet_data,
      54             :                                   struct proxy_auth_ctx);
      55           0 :             break;
      56             :         case SSS_PAM_ACCT_MGMT:
      57           0 :             ctx = talloc_get_type(be_ctx->bet_info[BET_ACCESS].pvt_bet_data,
      58             :                                   struct proxy_auth_ctx);
      59           0 :             break;
      60             :         case SSS_PAM_SETCRED:
      61             :         case SSS_PAM_OPEN_SESSION:
      62             :         case SSS_PAM_CLOSE_SESSION:
      63           0 :             pd->pam_status = PAM_SUCCESS;
      64           0 :             be_req_terminate(req, DP_ERR_OK, EOK, NULL);
      65           0 :             return;
      66             :         default:
      67           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported PAM task.\n");
      68           0 :             pd->pam_status = PAM_MODULE_UNKNOWN;
      69           0 :             be_req_terminate(req, DP_ERR_OK, EINVAL, "Unsupported PAM task");
      70           0 :             return;
      71             :     }
      72             : 
      73           0 :     client_ctx = talloc(req, struct proxy_client_ctx);
      74           0 :     if (client_ctx == NULL) {
      75           0 :         be_req_terminate(req, DP_ERR_FATAL, ENOMEM, NULL);
      76           0 :         return;
      77             :     }
      78           0 :     client_ctx->auth_ctx = ctx;
      79           0 :     client_ctx->be_req = req;
      80             : 
      81             :     /* Queue the request and spawn a child if there
      82             :      * is an available slot.
      83             :      */
      84           0 :     child_req = proxy_child_send(req, ctx, req);
      85           0 :     if (child_req == NULL) {
      86             :         /* Could not queue request
      87             :          * Return an error
      88             :          */
      89           0 :         be_req_terminate(req, DP_ERR_FATAL, EINVAL, "Could not queue request\n");
      90           0 :         return;
      91             :     }
      92           0 :     tevent_req_set_callback(child_req, proxy_child_done, client_ctx);
      93           0 :     return;
      94             : }
      95             : 
      96             : struct pc_init_ctx;
      97             : 
      98           0 : static int proxy_child_destructor(TALLOC_CTX *ctx)
      99             : {
     100           0 :     struct proxy_child_ctx *child_ctx =
     101             :             talloc_get_type(ctx, struct proxy_child_ctx);
     102             :     hash_key_t key;
     103             :     int hret;
     104             : 
     105           0 :     DEBUG(SSSDBG_TRACE_INTERNAL,
     106             :           "Removing proxy child id [%d]\n", child_ctx->id);
     107           0 :     key.type = HASH_KEY_ULONG;
     108           0 :     key.ul = child_ctx->id;
     109           0 :     hret = hash_delete(child_ctx->auth_ctx->request_table, &key);
     110           0 :     if (!(hret == HASH_SUCCESS ||
     111             :           hret == HASH_ERROR_KEY_NOT_FOUND)) {
     112           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     113             :               "Hash error [%d][%s]\n", hret, hash_error_string(hret));
     114             :         /* Nothing we can do about this, so just continue */
     115             :     }
     116           0 :     return 0;
     117             : }
     118             : 
     119             : static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
     120             :                                               struct proxy_child_ctx *child_ctx,
     121             :                                               struct proxy_auth_ctx *auth_ctx);
     122             : static void proxy_child_init_done(struct tevent_req *subreq);
     123           0 : static struct tevent_req *proxy_child_send(TALLOC_CTX *mem_ctx,
     124             :                                            struct proxy_auth_ctx *auth_ctx,
     125             :                                            struct be_req *be_req)
     126             : {
     127             :     struct tevent_req *req;
     128             :     struct tevent_req *subreq;
     129             :     struct proxy_child_ctx *state;
     130             :     int hret;
     131             :     hash_key_t key;
     132             :     hash_value_t value;
     133             :     uint32_t first;
     134             : 
     135           0 :     req = tevent_req_create(mem_ctx, &state, struct proxy_child_ctx);
     136           0 :     if (req == NULL) {
     137           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not send PAM request to child\n");
     138           0 :         return NULL;
     139             :     }
     140             : 
     141           0 :     state->be_req = be_req;
     142           0 :     state->auth_ctx = auth_ctx;
     143           0 :     state->pd = talloc_get_type(be_req_get_data(be_req), struct pam_data);
     144             : 
     145             :     /* Find an available key */
     146           0 :     key.type = HASH_KEY_ULONG;
     147           0 :     key.ul = auth_ctx->next_id;
     148             : 
     149           0 :     first = auth_ctx->next_id;
     150           0 :     while (auth_ctx->next_id == 0 ||
     151           0 :             hash_has_key(auth_ctx->request_table, &key)) {
     152             :         /* Handle overflow, zero is a reserved value
     153             :          * Also handle the unlikely case where the next ID
     154             :          * is still awaiting being run
     155             :          */
     156           0 :         auth_ctx->next_id++;
     157           0 :         key.ul = auth_ctx->next_id;
     158             : 
     159           0 :         if (auth_ctx->next_id == first) {
     160             :             /* We've looped through all possible integers! */
     161           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Serious error: queue is too long!\n");
     162           0 :             talloc_zfree(req);
     163           0 :             return NULL;
     164             :         }
     165             :     }
     166             : 
     167           0 :     state->id = auth_ctx->next_id;
     168           0 :     auth_ctx->next_id++;
     169             : 
     170           0 :     value.type = HASH_VALUE_PTR;
     171           0 :     value.ptr = req;
     172           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Queueing request [%lu]\n", key.ul);
     173           0 :     hret = hash_enter(auth_ctx->request_table,
     174             :                       &key, &value);
     175           0 :     if (hret != HASH_SUCCESS) {
     176           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not add request to the queue\n");
     177           0 :         talloc_zfree(req);
     178           0 :         return NULL;
     179             :     }
     180             : 
     181           0 :     talloc_set_destructor((TALLOC_CTX *) state,
     182             :                           proxy_child_destructor);
     183             : 
     184           0 :     if (auth_ctx->running < auth_ctx->max_children) {
     185             :         /* There's an available slot; start a child
     186             :          * to handle the request
     187             :          */
     188             : 
     189           0 :         auth_ctx->running++;
     190           0 :         subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);
     191           0 :         if (!subreq) {
     192           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not fork child process\n");
     193           0 :             auth_ctx->running--;
     194           0 :             talloc_zfree(req);
     195           0 :             return NULL;
     196             :         }
     197           0 :         tevent_req_set_callback(subreq, proxy_child_init_done, req);
     198             : 
     199           0 :         state->running = true;
     200             :     }
     201             :     else {
     202             :         /* If there was no available slot, it will be queued
     203             :          * until a slot is available
     204             :          */
     205           0 :         DEBUG(SSSDBG_TRACE_INTERNAL,
     206             :               "All available child slots are full, queuing request\n");
     207             :     }
     208           0 :     return req;
     209             : }
     210             : 
     211           0 : static int pc_init_destructor (TALLOC_CTX *ctx)
     212             : {
     213           0 :     struct pc_init_ctx *init_ctx =
     214             :             talloc_get_type(ctx, struct pc_init_ctx);
     215             : 
     216             :     /* If the init request has died, forcibly kill the child */
     217           0 :     kill(init_ctx->pid, SIGKILL);
     218           0 :     return 0;
     219             : }
     220             : 
     221             : static void pc_init_sig_handler(struct tevent_context *ev,
     222             :                            struct tevent_signal *sige, int signum,
     223             :                            int count, void *__siginfo, void *pvt);
     224             : static void pc_init_timeout(struct tevent_context *ev,
     225             :                             struct tevent_timer *te,
     226             :                             struct timeval t, void *ptr);
     227           0 : static struct tevent_req *proxy_child_init_send(TALLOC_CTX *mem_ctx,
     228             :                                               struct proxy_child_ctx *child_ctx,
     229             :                                               struct proxy_auth_ctx *auth_ctx)
     230             : {
     231             :     struct tevent_req *req;
     232             :     struct pc_init_ctx *state;
     233             :     char **proxy_child_args;
     234             :     struct timeval tv;
     235             :     errno_t ret;
     236             :     pid_t pid;
     237             : 
     238           0 :     req = tevent_req_create(mem_ctx, &state, struct pc_init_ctx);
     239           0 :     if (req == NULL) {
     240           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Could not create tevent_req\n");
     241           0 :         return NULL;
     242             :     }
     243             : 
     244           0 :     state->child_ctx = child_ctx;
     245             : 
     246           0 :     state->command = talloc_asprintf(req,
     247             :             "%s/proxy_child -d %#.4x --debug-timestamps=%d "
     248             :             "--debug-microseconds=%d%s --domain %s --id %d",
     249             :             SSSD_LIBEXEC_PATH, debug_level, debug_timestamps,
     250           0 :             debug_microseconds, (debug_to_file ? " --debug-to-files" : ""),
     251           0 :             auth_ctx->be->domain->name,
     252             :             child_ctx->id);
     253           0 :     if (state->command == NULL) {
     254           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_asprintf failed.\n");
     255           0 :         return NULL;
     256             :     }
     257             : 
     258           0 :     DEBUG(SSSDBG_TRACE_LIBS,
     259             :           "Starting proxy child with args [%s]\n", state->command);
     260             : 
     261           0 :     pid = fork();
     262           0 :     if (pid < 0) {
     263           0 :         ret = errno;
     264           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     265             :               "fork failed [%d][%s].\n", ret, strerror(ret));
     266           0 :         talloc_zfree(req);
     267           0 :         return NULL;
     268             :     }
     269             : 
     270           0 :     if (pid == 0) { /* child */
     271           0 :         proxy_child_args = parse_args(state->command);
     272           0 :         execvp(proxy_child_args[0], proxy_child_args);
     273             : 
     274           0 :         ret = errno;
     275           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     276             :               "Could not start proxy child [%s]: [%d][%s].\n",
     277             :                   state->command, ret, strerror(ret));
     278             : 
     279           0 :         _exit(1);
     280             :     }
     281             : 
     282             :     else { /* parent */
     283           0 :         state->pid = pid;
     284             :         /* Make sure to kill the child process if we abort */
     285           0 :         talloc_set_destructor((TALLOC_CTX *)state, pc_init_destructor);
     286             : 
     287           0 :         state->sige = tevent_add_signal(auth_ctx->be->ev, req,
     288             :                                         SIGCHLD, 0,
     289             :                                         pc_init_sig_handler, req);
     290           0 :         if (state->sige == NULL) {
     291           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n");
     292           0 :             talloc_zfree(req);
     293           0 :             return NULL;
     294             :         }
     295             : 
     296             :         /* Save the init request to the child context.
     297             :          * This is technically a layering violation,
     298             :          * but it's the only sane way to be able to
     299             :          * identify which client is which when it
     300             :          * connects to the backend in
     301             :          * client_registration()
     302             :          */
     303           0 :         child_ctx->init_req = req;
     304             : 
     305             :         /* Wait six seconds for the child to connect
     306             :          * This is because the connection handler will add
     307             :          * its own five-second timeout, and we don't want to
     308             :          * be faster here.
     309             :          */
     310           0 :         tv = tevent_timeval_current_ofs(6, 0);
     311           0 :         state->timeout = tevent_add_timer(auth_ctx->be->ev, req,
     312             :                                           tv, pc_init_timeout, req);
     313             : 
     314             :         /* processing will continue once the connection is received
     315             :          * in proxy_client_init()
     316             :          */
     317           0 :         return req;
     318             :     }
     319             : }
     320             : 
     321           0 : static void pc_init_sig_handler(struct tevent_context *ev,
     322             :                                 struct tevent_signal *sige, int signum,
     323             :                                 int count, void *__siginfo, void *pvt)
     324             : {
     325             :     int ret;
     326             :     int child_status;
     327             :     struct tevent_req *req;
     328             :     struct pc_init_ctx *init_ctx;
     329             : 
     330           0 :     if (count <= 0) {
     331           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     332             :               "SIGCHLD handler called with invalid child count\n");
     333           0 :         return;
     334             :     }
     335             : 
     336           0 :     req = talloc_get_type(pvt, struct tevent_req);
     337           0 :     init_ctx = tevent_req_data(req, struct pc_init_ctx);
     338             : 
     339           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Waiting for child [%d].\n", init_ctx->pid);
     340             : 
     341           0 :     errno = 0;
     342           0 :     ret = waitpid(init_ctx->pid, &child_status, WNOHANG);
     343             : 
     344           0 :     if (ret == -1) {
     345           0 :         ret = errno;
     346           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     347             :               "waitpid failed [%d][%s].\n", ret, strerror(ret));
     348           0 :     } else if (ret == 0) {
     349           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     350             :               "waitpid did not find a child with changed status.\n");
     351             :     } else {
     352           0 :         if (WIFEXITED(child_status)) {
     353           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     354             :                   "child [%d] exited with status [%d].\n", ret,
     355             :                       WEXITSTATUS(child_status));
     356           0 :             tevent_req_error(req, EIO);
     357           0 :         } else if (WIFSIGNALED(child_status)) {
     358           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     359             :                   "child [%d] was terminate by signal [%d].\n", ret,
     360             :                       WTERMSIG(child_status));
     361           0 :             tevent_req_error(req, EIO);
     362             :         } else {
     363           0 :             if (WIFSTOPPED(child_status)) {
     364           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     365             :                       "child [%d] was stopped by signal [%d].\n", ret,
     366             :                           WSTOPSIG(child_status));
     367             :             }
     368           0 :             if (WIFCONTINUED(child_status) == true) {
     369           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     370             :                       "child [%d] was resumed by delivery of SIGCONT.\n",
     371             :                           ret);
     372             :             }
     373           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     374             :                   "Child is still running, no new child is started.\n");
     375           0 :             return;
     376             :         }
     377             :     }
     378             : }
     379             : 
     380           0 : static void pc_init_timeout(struct tevent_context *ev,
     381             :                             struct tevent_timer *te,
     382             :                             struct timeval t, void *ptr)
     383             : {
     384             :     struct tevent_req *req;
     385             : 
     386           0 :     DEBUG(SSSDBG_OP_FAILURE, "Client timed out before Identification!\n");
     387           0 :     req = talloc_get_type(ptr, struct tevent_req);
     388           0 :     tevent_req_error(req, ETIMEDOUT);
     389           0 : }
     390             : 
     391           0 : static errno_t proxy_child_init_recv(struct tevent_req *req,
     392             :                                    pid_t *pid,
     393             :                                    struct sbus_connection **conn)
     394             : {
     395             :     struct pc_init_ctx *state;
     396             : 
     397           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     398             : 
     399           0 :     state = tevent_req_data(req, struct pc_init_ctx);
     400             : 
     401             :     /* Unset the destructor since we initialized successfully.
     402             :      * We don't want to kill the child now that it's properly
     403             :      * set up.
     404             :      */
     405           0 :     talloc_set_destructor((TALLOC_CTX *)state, NULL);
     406             : 
     407           0 :     *pid = state->pid;
     408           0 :     *conn = state->conn;
     409             : 
     410           0 :     return EOK;
     411             : }
     412             : 
     413             : struct proxy_child_sig_ctx {
     414             :     struct proxy_auth_ctx *auth_ctx;
     415             :     pid_t pid;
     416             : };
     417             : static void proxy_child_sig_handler(struct tevent_context *ev,
     418             :                                     struct tevent_signal *sige, int signum,
     419             :                                     int count, void *__siginfo, void *pvt);
     420             : static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
     421             :                                               struct proxy_auth_ctx *auth_ctx,
     422             :                                               struct sbus_connection *conn,
     423             :                                               struct pam_data *pd,
     424             :                                               pid_t pid);
     425             : static void proxy_pam_conv_done(struct tevent_req *subreq);
     426           0 : static void proxy_child_init_done(struct tevent_req *subreq) {
     427             :     int ret;
     428             :     struct tevent_signal *sige;
     429           0 :     struct tevent_req *req =
     430           0 :             tevent_req_callback_data(subreq, struct tevent_req);
     431           0 :     struct proxy_child_ctx *child_ctx =
     432           0 :             tevent_req_data(req, struct proxy_child_ctx);
     433             :     struct proxy_child_sig_ctx *sig_ctx;
     434             : 
     435           0 :     ret = proxy_child_init_recv(subreq, &child_ctx->pid, &child_ctx->conn);
     436           0 :     talloc_zfree(subreq);
     437           0 :     if (ret != EOK) {
     438           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Proxy child init failed [%d]\n", ret);
     439           0 :         tevent_req_error(req, ret);
     440           0 :         return;
     441             :     }
     442             : 
     443             :     /* An initialized child is available, awaiting the PAM command */
     444           0 :     subreq = proxy_pam_conv_send(req, child_ctx->auth_ctx,
     445             :                                  child_ctx->conn, child_ctx->pd,
     446             :                                  child_ctx->pid);
     447           0 :     if (!subreq) {
     448           0 :         DEBUG(SSSDBG_CRIT_FAILURE,"Could not start PAM conversation\n");
     449           0 :         tevent_req_error(req, EIO);
     450           0 :         return;
     451             :     }
     452           0 :     tevent_req_set_callback(subreq, proxy_pam_conv_done, req);
     453             : 
     454             :     /* Add a signal handler for the child under the auth_ctx,
     455             :      * that way if the child exits after completion of the
     456             :      * request, it will still be handled.
     457             :      */
     458           0 :     sig_ctx = talloc_zero(child_ctx->auth_ctx, struct proxy_child_sig_ctx);
     459           0 :     if(sig_ctx == NULL) {
     460           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n");
     461           0 :         tevent_req_error(req, ENOMEM);
     462           0 :         return;
     463             :     }
     464           0 :     sig_ctx->auth_ctx = child_ctx->auth_ctx;
     465           0 :     sig_ctx->pid = child_ctx->pid;
     466             : 
     467           0 :     sige = tevent_add_signal(child_ctx->auth_ctx->be->ev,
     468             :                              child_ctx->auth_ctx,
     469             :                              SIGCHLD, 0,
     470             :                              proxy_child_sig_handler,
     471             :                              sig_ctx);
     472           0 :     if (sige == NULL) {
     473           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_signal failed.\n");
     474           0 :         tevent_req_error(req, ENOMEM);
     475           0 :         return;
     476             :     }
     477             : 
     478             :     /* Steal the signal context onto the signal event
     479             :      * so that when the signal is freed, the context
     480             :      * will go with it.
     481             :      */
     482           0 :     talloc_steal(sige, sig_ctx);
     483             : }
     484             : 
     485             : static void remove_sige(struct tevent_context *ev,
     486             :                         struct tevent_immediate *imm,
     487             :                         void *pvt);
     488             : static void run_proxy_child_queue(struct tevent_context *ev,
     489             :                                   struct tevent_immediate *imm,
     490             :                                   void *pvt);
     491           0 : static void proxy_child_sig_handler(struct tevent_context *ev,
     492             :                                     struct tevent_signal *sige, int signum,
     493             :                                     int count, void *__siginfo, void *pvt)
     494             : {
     495             :     int ret;
     496             :     int child_status;
     497             :     struct proxy_child_sig_ctx *sig_ctx;
     498             :     struct tevent_immediate *imm;
     499             :     struct tevent_immediate *imm2;
     500             : 
     501           0 :     if (count <= 0) {
     502           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     503             :               "SIGCHLD handler called with invalid child count\n");
     504           0 :         return;
     505             :     }
     506             : 
     507           0 :     sig_ctx = talloc_get_type(pvt, struct proxy_child_sig_ctx);
     508           0 :     DEBUG(SSSDBG_TRACE_LIBS, "Waiting for child [%d].\n", sig_ctx->pid);
     509             : 
     510           0 :     errno = 0;
     511           0 :     ret = waitpid(sig_ctx->pid, &child_status, WNOHANG);
     512             : 
     513           0 :     if (ret == -1) {
     514           0 :         ret = errno;
     515           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     516             :               "waitpid failed [%d][%s].\n", ret, strerror(ret));
     517           0 :     } else if (ret == 0) {
     518           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     519             :               "waitpid did not found a child with changed status.\n");
     520             :     } else {
     521           0 :         if (WIFEXITED(child_status)) {
     522           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     523             :                   "child [%d] exited with status [%d].\n", ret,
     524             :                       WEXITSTATUS(child_status));
     525           0 :         } else if (WIFSIGNALED(child_status) == true) {
     526           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     527             :                   "child [%d] was terminated by signal [%d].\n", ret,
     528             :                       WTERMSIG(child_status));
     529             :         } else {
     530           0 :             if (WIFSTOPPED(child_status)) {
     531           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     532             :                       "child [%d] was stopped by signal [%d].\n", ret,
     533             :                           WSTOPSIG(child_status));
     534             :             }
     535           0 :             if (WIFCONTINUED(child_status) == true) {
     536           0 :                 DEBUG(SSSDBG_CRIT_FAILURE,
     537             :                       "child [%d] was resumed by delivery of SIGCONT.\n",
     538             :                           ret);
     539             :             }
     540           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     541             :                   "Child is still running, no new child is started.\n");
     542           0 :             return;
     543             :         }
     544             : 
     545           0 :         imm = tevent_create_immediate(ev);
     546           0 :         if (imm == NULL) {
     547           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
     548           0 :             return;
     549             :         }
     550             : 
     551           0 :         tevent_schedule_immediate(imm, ev, run_proxy_child_queue,
     552             :                                   sig_ctx->auth_ctx);
     553             : 
     554             :         /* schedule another immediate timer to delete the sigchld handler */
     555           0 :         imm2 = tevent_create_immediate(ev);
     556           0 :         if (imm2 == NULL) {
     557           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
     558           0 :             return;
     559             :         }
     560             : 
     561           0 :         tevent_schedule_immediate(imm2, ev, remove_sige, sige);
     562             :     }
     563             : 
     564           0 :     return;
     565             : }
     566             : 
     567           0 : static void remove_sige(struct tevent_context *ev,
     568             :                         struct tevent_immediate *imm,
     569             :                         void *pvt)
     570             : {
     571           0 :     talloc_free(pvt);
     572           0 : }
     573             : 
     574             : struct proxy_conv_ctx {
     575             :     struct proxy_auth_ctx *auth_ctx;
     576             :     struct sbus_connection *conn;
     577             :     struct pam_data *pd;
     578             :     pid_t pid;
     579             : };
     580             : static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr);
     581           0 : static struct tevent_req *proxy_pam_conv_send(TALLOC_CTX *mem_ctx,
     582             :                                               struct proxy_auth_ctx *auth_ctx,
     583             :                                               struct sbus_connection *conn,
     584             :                                               struct pam_data *pd,
     585             :                                               pid_t pid)
     586             : {
     587             :     errno_t ret;
     588             :     bool dp_ret;
     589             :     DBusMessage *msg;
     590             :     struct tevent_req *req;
     591             :     struct proxy_conv_ctx *state;
     592             : 
     593           0 :     req = tevent_req_create(mem_ctx, &state, struct proxy_conv_ctx);
     594           0 :     if (req == NULL) {
     595           0 :         return NULL;
     596             :     }
     597             : 
     598           0 :     state->auth_ctx = auth_ctx;
     599           0 :     state->conn = conn;
     600           0 :     state->pd = pd;
     601           0 :     state->pid = pid;
     602             : 
     603           0 :     msg = dbus_message_new_method_call(NULL,
     604             :                                        DP_PATH,
     605             :                                        DATA_PROVIDER_IFACE,
     606             :                                        DATA_PROVIDER_IFACE_PAMHANDLER);
     607           0 :     if (msg == NULL) {
     608           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "dbus_message_new_method_call failed.\n");
     609           0 :         talloc_zfree(req);
     610           0 :         return NULL;
     611             :     }
     612             : 
     613           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Sending request with the following data:\n");
     614           0 :     DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
     615             : 
     616           0 :     dp_ret = dp_pack_pam_request(msg, pd);
     617           0 :     if (!dp_ret) {
     618           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Failed to build message\n");
     619           0 :         dbus_message_unref(msg);
     620           0 :         talloc_zfree(req);
     621           0 :         return NULL;
     622             :     }
     623             : 
     624           0 :     ret = sbus_conn_send(state->conn, msg, state->auth_ctx->timeout_ms,
     625             :                          proxy_pam_conv_reply, req, NULL);
     626           0 :     if (ret != EOK) {
     627           0 :         dbus_message_unref(msg);
     628           0 :         talloc_zfree(req);
     629           0 :         return NULL;
     630             :     }
     631             : 
     632           0 :     dbus_message_unref(msg);
     633           0 :     return req;
     634             : }
     635             : 
     636           0 : static void proxy_pam_conv_reply(DBusPendingCall *pending, void *ptr)
     637             : {
     638             :     struct tevent_req *req;
     639             :     struct proxy_conv_ctx *state;
     640             :     DBusError dbus_error;
     641             :     DBusMessage *reply;
     642             :     int type;
     643             :     int ret;
     644             : 
     645           0 :     DEBUG(SSSDBG_TRACE_INTERNAL, "Handling pam conversation reply\n");
     646             : 
     647           0 :     req = talloc_get_type(ptr, struct tevent_req);
     648           0 :     state = tevent_req_data(req, struct proxy_conv_ctx);
     649             : 
     650           0 :     dbus_error_init(&dbus_error);
     651             : 
     652           0 :     reply = dbus_pending_call_steal_reply(pending);
     653           0 :     dbus_pending_call_unref(pending);
     654           0 :     if (reply == NULL) {
     655           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     656             :               "Severe error. A reply callback was called but no reply was"
     657             :                   "received and no timeout occurred\n");
     658           0 :         state->pd->pam_status = PAM_SYSTEM_ERR;
     659           0 :         tevent_req_error(req, EIO);
     660             :     }
     661             : 
     662           0 :     type = dbus_message_get_type(reply);
     663           0 :     switch (type) {
     664             :         case DBUS_MESSAGE_TYPE_METHOD_RETURN:
     665           0 :             ret = dp_unpack_pam_response(reply, state->pd, &dbus_error);
     666           0 :             if (!ret) {
     667           0 :                 DEBUG(SSSDBG_FATAL_FAILURE, "Failed to parse reply.\n");
     668           0 :                 state->pd->pam_status = PAM_SYSTEM_ERR;
     669           0 :                 dbus_message_unref(reply);
     670           0 :                 tevent_req_error(req, EIO);
     671           0 :                 return;
     672             :             }
     673           0 :             DEBUG(SSSDBG_CONF_SETTINGS, "received: [%d][%s]\n",
     674             :                       state->pd->pam_status,
     675             :                       state->pd->domain);
     676           0 :             break;
     677             :         case DBUS_MESSAGE_TYPE_ERROR:
     678           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Reply error [%s].\n",
     679             :                     dbus_message_get_error_name(reply));
     680           0 :             state->pd->pam_status = PAM_SYSTEM_ERR;
     681           0 :             break;
     682             :         default:
     683           0 :             DEBUG(SSSDBG_FATAL_FAILURE, "Default... what now?.\n");
     684           0 :             state->pd->pam_status = PAM_SYSTEM_ERR;
     685             :     }
     686           0 :     dbus_message_unref(reply);
     687             : 
     688             :     /* Kill the child */
     689           0 :     kill(state->pid, SIGKILL);
     690             : 
     691             :     /* Conversation is finished */
     692           0 :     tevent_req_done(req);
     693             : }
     694             : 
     695           0 : static errno_t proxy_pam_conv_recv(struct tevent_req *req)
     696             : {
     697           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     698             : 
     699           0 :     return EOK;
     700             : }
     701             : 
     702           0 : static void proxy_pam_conv_done(struct tevent_req *subreq)
     703             : {
     704             :     struct tevent_req *req;
     705             :     int ret;
     706             : 
     707           0 :     req = tevent_req_callback_data(subreq, struct tevent_req);
     708             : 
     709           0 :     ret = proxy_pam_conv_recv(subreq);
     710           0 :     talloc_zfree(subreq);
     711           0 :     if (ret != EOK) {
     712           0 :         DEBUG(SSSDBG_TRACE_FUNC, "Proxy PAM conversation failed [%d]\n", ret);
     713           0 :         tevent_req_error(req, ret);
     714           0 :         return;
     715             :     }
     716             : 
     717           0 :     tevent_req_done(req);
     718             : }
     719             : 
     720           0 : static int proxy_child_recv(struct tevent_req *req,
     721             :                           TALLOC_CTX *mem_ctx,
     722             :                           struct pam_data **pd)
     723             : {
     724             :     struct proxy_child_ctx *ctx;
     725             : 
     726           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     727             : 
     728           0 :     ctx = tevent_req_data(req, struct proxy_child_ctx);
     729           0 :     *pd = talloc_steal(mem_ctx, ctx->pd);
     730             : 
     731           0 :     return EOK;
     732             : }
     733             : 
     734           0 : static void proxy_child_done(struct tevent_req *req)
     735             : {
     736           0 :     struct proxy_client_ctx *client_ctx =
     737           0 :             tevent_req_callback_data(req, struct proxy_client_ctx);
     738           0 :     struct be_ctx *be_ctx = be_req_get_be_ctx(client_ctx->be_req);
     739           0 :     struct pam_data *pd = NULL;
     740             :     const char *password;
     741             :     int ret;
     742             :     struct tevent_immediate *imm;
     743             : 
     744           0 :     ret = proxy_child_recv(req, client_ctx, &pd);
     745           0 :     talloc_zfree(req);
     746             : 
     747             :     /* Start the next auth in the queue, if any */
     748           0 :     client_ctx->auth_ctx->running--;
     749           0 :     imm = tevent_create_immediate(be_ctx->ev);
     750           0 :     if (imm == NULL) {
     751           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_create_immediate failed.\n");
     752             :         /* We'll still finish the current request, but we're
     753             :          * likely to have problems if there are queued events
     754             :          * if we've gotten into this state.
     755             :          * Hopefully this is impossible, since freeing req
     756             :          * above should guarantee that we have enough memory
     757             :          * to create this immediate event.
     758             :          */
     759             :     } else {
     760           0 :         tevent_schedule_immediate(imm, be_ctx->ev,
     761             :                                   run_proxy_child_queue,
     762             :                                   client_ctx->auth_ctx);
     763             :     }
     764             : 
     765           0 :     if (ret != EOK) {
     766             :         /* Pam child failed */
     767           0 :         be_req_terminate(client_ctx->be_req, DP_ERR_FATAL, ret,
     768             :                     "PAM child failed");
     769           0 :         return;
     770             :     }
     771             : 
     772             :     /* Check if we need to save the cached credentials */
     773           0 :     if ((pd->cmd == SSS_PAM_AUTHENTICATE || pd->cmd == SSS_PAM_CHAUTHTOK) &&
     774           0 :         (pd->pam_status == PAM_SUCCESS) && be_ctx->domain->cache_credentials) {
     775             : 
     776           0 :         ret = sss_authtok_get_password(pd->authtok, &password, NULL);
     777           0 :         if (ret) {
     778             :             /* password caching failures are not fatal errors */
     779           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password\n");
     780           0 :             goto done;
     781             :         }
     782             : 
     783           0 :         ret = sysdb_cache_password(be_ctx->domain, pd->user, password);
     784             : 
     785             :         /* password caching failures are not fatal errors */
     786             :         /* so we just log it any return */
     787           0 :         if (ret != EOK) {
     788           0 :             DEBUG(SSSDBG_OP_FAILURE, "Failed to cache password (%d)[%s]!?\n",
     789             :                       ret, strerror(ret));
     790             :         }
     791             :     }
     792             : 
     793             : done:
     794           0 :     be_req_terminate(client_ctx->be_req, DP_ERR_OK, EOK, NULL);
     795             : }
     796             : 
     797           0 : static void run_proxy_child_queue(struct tevent_context *ev,
     798             :                                   struct tevent_immediate *imm,
     799             :                                   void *pvt)
     800             : {
     801             :     struct proxy_auth_ctx *auth_ctx;
     802             :     struct hash_iter_context_t *iter;
     803             :     struct hash_entry_t *entry;
     804             :     struct tevent_req *req;
     805             :     struct tevent_req *subreq;
     806             :     struct proxy_child_ctx *state;
     807             : 
     808           0 :     auth_ctx = talloc_get_type(pvt, struct proxy_auth_ctx);
     809             : 
     810             :     /* Launch next queued request */
     811           0 :     iter = new_hash_iter_context(auth_ctx->request_table);
     812           0 :     while ((entry = iter->next(iter)) != NULL) {
     813           0 :         req = talloc_get_type(entry->value.ptr, struct tevent_req);
     814           0 :         state = tevent_req_data(req, struct proxy_child_ctx);
     815           0 :         if (!state->running) {
     816           0 :             break;
     817             :         }
     818             :     }
     819           0 :     free(iter);
     820             : 
     821           0 :     if (!entry) {
     822             :         /* Nothing pending on the queue */
     823           0 :         return;
     824             :     }
     825             : 
     826           0 :     if (auth_ctx->running < auth_ctx->max_children) {
     827             :         /* There's an available slot; start a child
     828             :          * to handle the request
     829             :          */
     830           0 :         auth_ctx->running++;
     831           0 :         subreq = proxy_child_init_send(auth_ctx, state, auth_ctx);
     832           0 :         if (!subreq) {
     833           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not fork child process\n");
     834           0 :             auth_ctx->running--;
     835           0 :             talloc_zfree(req);
     836           0 :             return;
     837             :         }
     838           0 :         tevent_req_set_callback(subreq, proxy_child_init_done, req);
     839             : 
     840           0 :         state->running = true;
     841             :     }
     842             : }

Generated by: LCOV version 1.10