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

Generated by: LCOV version 1.10