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

          Line data    Source code
       1             : /*
       2             :     SSSD
       3             : 
       4             :     Kerberos 5 Backend Module - Manage krb5_child
       5             : 
       6             :     Authors:
       7             :         Sumit Bose <sbose@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 "util/util.h"
      26             : #include "util/child_common.h"
      27             : #include "providers/krb5/krb5_common.h"
      28             : #include "providers/krb5/krb5_auth.h"
      29             : #include "src/providers/krb5/krb5_utils.h"
      30             : 
      31             : #ifndef KRB5_CHILD_DIR
      32             : #ifndef SSSD_LIBEXEC_PATH
      33             : #error "SSSD_LIBEXEC_PATH not defined"
      34             : #endif  /* SSSD_LIBEXEC_PATH */
      35             : 
      36             : #define KRB5_CHILD_DIR SSSD_LIBEXEC_PATH
      37             : #endif /* KRB5_CHILD_DIR */
      38             : 
      39             : #define KRB5_CHILD KRB5_CHILD_DIR"/krb5_child"
      40             : 
      41             : #define TIME_T_MAX LONG_MAX
      42             : #define int64_to_time_t(val) ((time_t)((val) < TIME_T_MAX ? val : TIME_T_MAX))
      43             : 
      44             : struct handle_child_state {
      45             :     struct tevent_context *ev;
      46             :     struct krb5child_req *kr;
      47             :     uint8_t *buf;
      48             :     ssize_t len;
      49             : 
      50             :     struct tevent_timer *timeout_handler;
      51             :     pid_t child_pid;
      52             : 
      53             :     struct child_io_fds *io;
      54             : };
      55             : 
      56           0 : static errno_t pack_authtok(struct io_buffer *buf, size_t *rp,
      57             :                             struct sss_auth_token *tok)
      58             : {
      59             :     uint32_t auth_token_type;
      60           0 :     uint32_t auth_token_length = 0;
      61             :     const char *data;
      62             :     size_t len;
      63           0 :     errno_t ret = EOK;
      64             : 
      65           0 :     auth_token_type = sss_authtok_get_type(tok);
      66             : 
      67           0 :     switch (auth_token_type) {
      68             :     case SSS_AUTHTOK_TYPE_EMPTY:
      69           0 :         auth_token_length = 0;
      70           0 :         data = "";
      71           0 :         break;
      72             :     case SSS_AUTHTOK_TYPE_PASSWORD:
      73           0 :         ret = sss_authtok_get_password(tok, &data, &len);
      74           0 :         auth_token_length = len + 1;
      75           0 :         break;
      76             :     case SSS_AUTHTOK_TYPE_CCFILE:
      77           0 :         ret = sss_authtok_get_ccfile(tok, &data, &len);
      78           0 :         auth_token_length = len + 1;
      79           0 :         break;
      80             :     case SSS_AUTHTOK_TYPE_2FA:
      81           0 :         data = (char *) sss_authtok_get_data(tok);
      82           0 :         auth_token_length = sss_authtok_get_size(tok);
      83           0 :         break;
      84             :     default:
      85           0 :         ret = EINVAL;
      86             :     }
      87             : 
      88           0 :     if (ret == EOK) {
      89           0 :         SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_type, rp);
      90           0 :         SAFEALIGN_COPY_UINT32(&buf->data[*rp], &auth_token_length, rp);
      91           0 :         safealign_memcpy(&buf->data[*rp], data, auth_token_length, rp);
      92             :     }
      93             : 
      94           0 :     return ret;
      95             : }
      96             : 
      97           0 : static errno_t create_send_buffer(struct krb5child_req *kr,
      98             :                                   struct io_buffer **io_buf)
      99             : {
     100             :     struct io_buffer *buf;
     101             :     size_t rp;
     102             :     const char *keytab;
     103             :     uint32_t validate;
     104             :     uint32_t send_pac;
     105             :     uint32_t use_enterprise_principal;
     106           0 :     size_t username_len = 0;
     107             :     errno_t ret;
     108             : 
     109           0 :     keytab = dp_opt_get_cstring(kr->krb5_ctx->opts, KRB5_KEYTAB);
     110           0 :     if (keytab == NULL) {
     111           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing keytab option.\n");
     112           0 :         return EINVAL;
     113             :     }
     114             : 
     115           0 :     validate = dp_opt_get_bool(kr->krb5_ctx->opts, KRB5_VALIDATE) ? 1 : 0;
     116             : 
     117             :     /* Always send PAC except for local IPA users and IPA server mode */
     118           0 :     switch (kr->krb5_ctx->config_type) {
     119             :         case K5C_IPA_CLIENT:
     120           0 :             send_pac = kr->upn_from_different_realm ? 1 : 0;
     121           0 :             break;
     122             :         case K5C_IPA_SERVER:
     123           0 :             send_pac = 0;
     124           0 :             break;
     125             :         default:
     126           0 :             send_pac = 1;
     127           0 :             break;
     128             :     }
     129             : 
     130           0 :     if (kr->pd->cmd == SSS_CMD_RENEW || kr->is_offline) {
     131           0 :         use_enterprise_principal = false;
     132             :     } else {
     133           0 :         use_enterprise_principal = dp_opt_get_bool(kr->krb5_ctx->opts,
     134             :                                          KRB5_USE_ENTERPRISE_PRINCIPAL) ? 1 : 0;
     135             :     }
     136             : 
     137           0 :     buf = talloc(kr, struct io_buffer);
     138           0 :     if (buf == NULL) {
     139           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     140           0 :         return ENOMEM;
     141             :     }
     142             : 
     143           0 :     buf->size = 8*sizeof(uint32_t) + strlen(kr->upn);
     144             : 
     145           0 :     if (kr->pd->cmd == SSS_PAM_AUTHENTICATE ||
     146           0 :         kr->pd->cmd == SSS_CMD_RENEW ||
     147           0 :         kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
     148           0 :         kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
     149           0 :         buf->size += 4*sizeof(uint32_t) + strlen(kr->ccname) + strlen(keytab) +
     150           0 :                      sss_authtok_get_size(kr->pd->authtok);
     151             : 
     152           0 :         buf->size += sizeof(uint32_t);
     153           0 :         if (kr->old_ccname) {
     154           0 :             buf->size += strlen(kr->old_ccname);
     155             :         }
     156             :     }
     157             : 
     158           0 :     if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
     159           0 :         buf->size += 2*sizeof(uint32_t) +
     160           0 :                      sss_authtok_get_size(kr->pd->newauthtok);
     161             :     }
     162             : 
     163           0 :     if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
     164           0 :         username_len = strlen(kr->pd->user);
     165           0 :         buf->size += sizeof(uint32_t) + username_len;
     166             :     }
     167             : 
     168           0 :     buf->data = talloc_size(kr, buf->size);
     169           0 :     if (buf->data == NULL) {
     170           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc_size failed.\n");
     171           0 :         talloc_free(buf);
     172           0 :         return ENOMEM;
     173             :     }
     174             : 
     175           0 :     rp = 0;
     176           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->pd->cmd, &rp);
     177           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->uid, &rp);
     178           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->gid, &rp);
     179           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &validate, &rp);
     180           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &kr->is_offline, &rp);
     181           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &send_pac, &rp);
     182           0 :     SAFEALIGN_COPY_UINT32(&buf->data[rp], &use_enterprise_principal, &rp);
     183             : 
     184           0 :     SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->upn), &rp);
     185           0 :     safealign_memcpy(&buf->data[rp], kr->upn, strlen(kr->upn), &rp);
     186             : 
     187           0 :     if (kr->pd->cmd == SSS_PAM_AUTHENTICATE ||
     188           0 :         kr->pd->cmd == SSS_CMD_RENEW ||
     189           0 :         kr->pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM ||
     190           0 :         kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
     191           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->ccname), &rp);
     192           0 :         safealign_memcpy(&buf->data[rp], kr->ccname, strlen(kr->ccname), &rp);
     193             : 
     194           0 :         if (kr->old_ccname) {
     195           0 :             SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(kr->old_ccname), &rp);
     196           0 :             safealign_memcpy(&buf->data[rp], kr->old_ccname,
     197             :                              strlen(kr->old_ccname), &rp);
     198             :         } else {
     199           0 :             SAFEALIGN_SET_UINT32(&buf->data[rp], 0, &rp);
     200             :         }
     201             : 
     202           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], strlen(keytab), &rp);
     203           0 :         safealign_memcpy(&buf->data[rp], keytab, strlen(keytab), &rp);
     204             : 
     205           0 :         ret = pack_authtok(buf, &rp, kr->pd->authtok);
     206           0 :         if (ret) {
     207           0 :             return ret;
     208             :         }
     209             :     }
     210             : 
     211           0 :     if (kr->pd->cmd == SSS_PAM_CHAUTHTOK) {
     212           0 :         ret = pack_authtok(buf, &rp, kr->pd->newauthtok);
     213           0 :         if (ret) {
     214           0 :             return ret;
     215             :         }
     216             :     }
     217             : 
     218           0 :     if (kr->pd->cmd == SSS_PAM_ACCT_MGMT) {
     219           0 :         SAFEALIGN_SET_UINT32(&buf->data[rp], username_len, &rp);
     220           0 :         safealign_memcpy(&buf->data[rp], kr->pd->user, username_len, &rp);
     221             :     }
     222             : 
     223           0 :     *io_buf = buf;
     224             : 
     225           0 :     return EOK;
     226             : }
     227             : 
     228             : 
     229           0 : static void krb5_child_timeout(struct tevent_context *ev,
     230             :                                struct tevent_timer *te,
     231             :                                struct timeval tv, void *pvt)
     232             : {
     233           0 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     234           0 :     struct handle_child_state *state = tevent_req_data(req,
     235             :                                                      struct handle_child_state);
     236             :     int ret;
     237             : 
     238           0 :     if (state->timeout_handler == NULL) {
     239           0 :         return;
     240             :     }
     241             : 
     242           0 :     DEBUG(SSSDBG_IMPORTANT_INFO,
     243             :           "Timeout for child [%d] reached. In case KDC is distant or network "
     244             :            "is slow you may consider increasing value of krb5_auth_timeout.\n",
     245             :            state->child_pid);
     246             : 
     247           0 :     ret = kill(state->child_pid, SIGKILL);
     248           0 :     if (ret == -1) {
     249           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     250             :               "kill failed [%d][%s].\n", errno, strerror(errno));
     251             :     }
     252             : 
     253           0 :     tevent_req_error(req, ETIMEDOUT);
     254             : }
     255             : 
     256           0 : static errno_t activate_child_timeout_handler(struct tevent_req *req,
     257             :                                               struct tevent_context *ev,
     258             :                                               const uint32_t timeout_seconds)
     259             : {
     260             :     struct timeval tv;
     261           0 :     struct handle_child_state *state = tevent_req_data(req,
     262             :                                                      struct handle_child_state);
     263             : 
     264           0 :     tv = tevent_timeval_current();
     265           0 :     tv = tevent_timeval_add(&tv, timeout_seconds, 0);
     266           0 :     state->timeout_handler = tevent_add_timer(ev, state, tv,
     267             :                                            krb5_child_timeout, req);
     268           0 :     if (state->timeout_handler == NULL) {
     269           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "tevent_add_timer failed.\n");
     270           0 :         return ENOMEM;
     271             :     }
     272             : 
     273           0 :     return EOK;
     274             : }
     275             : 
     276           0 : static errno_t fork_child(struct tevent_req *req)
     277             : {
     278           0 :     int pipefd_to_child[2] = PIPE_INIT;
     279           0 :     int pipefd_from_child[2] = PIPE_INIT;
     280             :     pid_t pid;
     281             :     errno_t ret;
     282           0 :     struct handle_child_state *state = tevent_req_data(req,
     283             :                                                      struct handle_child_state);
     284             :     const char *k5c_extra_args[3];
     285             : 
     286           0 :     k5c_extra_args[0] = talloc_asprintf(state, "--fast-ccache-uid=%"SPRIuid, getuid());
     287           0 :     k5c_extra_args[1] = talloc_asprintf(state, "--fast-ccache-gid=%"SPRIgid, getgid());
     288           0 :     k5c_extra_args[2] = NULL;
     289           0 :     if (k5c_extra_args[0] == NULL || k5c_extra_args[1] == NULL) {
     290           0 :         return ENOMEM;
     291             :     }
     292             : 
     293           0 :     ret = pipe(pipefd_from_child);
     294           0 :     if (ret == -1) {
     295           0 :         ret = errno;
     296           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     297             :               "pipe failed [%d][%s].\n", errno, strerror(errno));
     298           0 :         goto fail;
     299             :     }
     300           0 :     ret = pipe(pipefd_to_child);
     301           0 :     if (ret == -1) {
     302           0 :         ret = errno;
     303           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     304             :               "pipe failed [%d][%s].\n", errno, strerror(errno));
     305           0 :         goto fail;
     306             :     }
     307             : 
     308           0 :     pid = fork();
     309             : 
     310           0 :     if (pid == 0) { /* child */
     311           0 :         exec_child_ex(state,
     312             :                       pipefd_to_child, pipefd_from_child,
     313           0 :                       KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
     314             :                       k5c_extra_args, false, STDIN_FILENO, STDOUT_FILENO);
     315             : 
     316             :         /* We should never get here */
     317           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec KRB5 child\n");
     318           0 :     } else if (pid > 0) { /* parent */
     319           0 :         state->child_pid = pid;
     320           0 :         state->io->read_from_child_fd = pipefd_from_child[0];
     321           0 :         PIPE_FD_CLOSE(pipefd_from_child[1]);
     322           0 :         state->io->write_to_child_fd = pipefd_to_child[1];
     323           0 :         PIPE_FD_CLOSE(pipefd_to_child[0]);
     324           0 :         sss_fd_nonblocking(state->io->read_from_child_fd);
     325           0 :         sss_fd_nonblocking(state->io->write_to_child_fd);
     326             : 
     327           0 :         ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
     328           0 :         if (ret != EOK) {
     329           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     330             :                   "Could not set up child signal handler\n");
     331           0 :             goto fail;
     332             :         }
     333             : 
     334           0 :         ret = activate_child_timeout_handler(req, state->ev,
     335           0 :                   dp_opt_get_int(state->kr->krb5_ctx->opts, KRB5_AUTH_TIMEOUT));
     336           0 :         if (ret != EOK) {
     337           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     338             :                   "activate_child_timeout_handler failed.\n");
     339             :         }
     340             : 
     341             :     } else { /* error */
     342           0 :         ret = errno;
     343           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     344             :               "fork failed [%d][%s].\n", errno, strerror(ret));
     345           0 :         goto fail;
     346             :     }
     347             : 
     348           0 :     return EOK;
     349             : 
     350             : fail:
     351           0 :     PIPE_CLOSE(pipefd_from_child);
     352           0 :     PIPE_CLOSE(pipefd_to_child);
     353           0 :     return ret;
     354             : }
     355             : 
     356             : static void handle_child_step(struct tevent_req *subreq);
     357             : static void handle_child_done(struct tevent_req *subreq);
     358             : 
     359           0 : struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
     360             :                                      struct tevent_context *ev,
     361             :                                      struct krb5child_req *kr)
     362             : {
     363             :     struct tevent_req *req, *subreq;
     364             :     struct handle_child_state *state;
     365             :     int ret;
     366           0 :     struct io_buffer *buf = NULL;
     367             : 
     368           0 :     req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
     369           0 :     if (req == NULL) {
     370           0 :         return NULL;
     371             :     }
     372             : 
     373           0 :     state->ev = ev;
     374           0 :     state->kr = kr;
     375           0 :     state->buf = NULL;
     376           0 :     state->len = 0;
     377           0 :     state->child_pid = -1;
     378           0 :     state->timeout_handler = NULL;
     379             : 
     380           0 :     state->io = talloc(state, struct child_io_fds);
     381           0 :     if (state->io == NULL) {
     382           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     383           0 :         ret = ENOMEM;
     384           0 :         goto fail;
     385             :     }
     386           0 :     state->io->write_to_child_fd = -1;
     387           0 :     state->io->read_from_child_fd = -1;
     388           0 :     talloc_set_destructor((void *) state->io, child_io_destructor);
     389             : 
     390           0 :     ret = create_send_buffer(kr, &buf);
     391           0 :     if (ret != EOK) {
     392           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "create_send_buffer failed.\n");
     393           0 :         goto fail;
     394             :     }
     395             : 
     396           0 :     ret = fork_child(req);
     397           0 :     if (ret != EOK) {
     398           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "fork_child failed.\n");
     399           0 :         goto fail;
     400             :     }
     401             : 
     402           0 :     subreq = write_pipe_send(state, ev, buf->data, buf->size,
     403           0 :                              state->io->write_to_child_fd);
     404           0 :     if (!subreq) {
     405           0 :         ret = ENOMEM;
     406           0 :         goto fail;
     407             :     }
     408           0 :     tevent_req_set_callback(subreq, handle_child_step, req);
     409             : 
     410           0 :     return req;
     411             : 
     412             : fail:
     413           0 :     tevent_req_error(req, ret);
     414           0 :     tevent_req_post(req, ev);
     415           0 :     return req;
     416             : }
     417             : 
     418           0 : static void handle_child_step(struct tevent_req *subreq)
     419             : {
     420           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     421             :                                                       struct tevent_req);
     422           0 :     struct handle_child_state *state = tevent_req_data(req,
     423             :                                                     struct handle_child_state);
     424             :     int ret;
     425             : 
     426           0 :     ret = write_pipe_recv(subreq);
     427           0 :     talloc_zfree(subreq);
     428           0 :     if (ret != EOK) {
     429           0 :         tevent_req_error(req, ret);
     430           0 :         return;
     431             :     }
     432             : 
     433           0 :     PIPE_FD_CLOSE(state->io->write_to_child_fd);
     434             : 
     435           0 :     subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
     436           0 :     if (!subreq) {
     437           0 :         tevent_req_error(req, ENOMEM);
     438           0 :         return;
     439             :     }
     440           0 :     tevent_req_set_callback(subreq, handle_child_done, req);
     441             : }
     442             : 
     443           0 : static void handle_child_done(struct tevent_req *subreq)
     444             : {
     445           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     446             :                                                       struct tevent_req);
     447           0 :     struct handle_child_state *state = tevent_req_data(req,
     448             :                                                     struct handle_child_state);
     449             :     int ret;
     450             : 
     451           0 :     talloc_zfree(state->timeout_handler);
     452             : 
     453           0 :     ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
     454           0 :     talloc_zfree(subreq);
     455           0 :     if (ret != EOK) {
     456           0 :         tevent_req_error(req, ret);
     457           0 :         return;
     458             :     }
     459             : 
     460           0 :     PIPE_FD_CLOSE(state->io->read_from_child_fd);
     461             : 
     462           0 :     tevent_req_done(req);
     463           0 :     return;
     464             : }
     465             : 
     466           0 : int handle_child_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     467             :                       uint8_t **buf, ssize_t *len)
     468             : {
     469           0 :     struct handle_child_state *state = tevent_req_data(req,
     470             :                                                     struct handle_child_state);
     471             : 
     472           0 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     473             : 
     474           0 :     *buf = talloc_move(mem_ctx, &state->buf);
     475           0 :     *len = state->len;
     476             : 
     477           0 :     return EOK;
     478             : }
     479             : 
     480             : errno_t
     481           0 : parse_krb5_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf, ssize_t len,
     482             :                           struct pam_data *pd, int pwd_exp_warning,
     483             :                           struct krb5_child_response **_res)
     484             : {
     485             :     ssize_t pref_len;
     486             :     size_t p;
     487             :     errno_t ret;
     488             :     bool skip;
     489           0 :     char *ccname = NULL;
     490           0 :     size_t ccname_len = 0;
     491             :     int32_t msg_status;
     492             :     int32_t msg_type;
     493             :     int32_t msg_len;
     494             :     int64_t time_data;
     495             :     struct tgt_times tgtt;
     496             :     uint32_t expiration;
     497             :     uint32_t msg_subtype;
     498             :     struct krb5_child_response *res;
     499           0 :     const char *upn = NULL;
     500           0 :     size_t upn_len = 0;
     501           0 :     bool otp = false;
     502             : 
     503           0 :     if ((size_t) len < sizeof(int32_t)) {
     504           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "message too short.\n");
     505           0 :         return EINVAL;
     506             :     }
     507             : 
     508           0 :     memset(&tgtt, 0, sizeof(struct tgt_times));
     509             : 
     510           0 :     if (pwd_exp_warning < 0) {
     511           0 :         pwd_exp_warning = KERBEROS_PWEXPIRE_WARNING_TIME;
     512             :     }
     513             : 
     514             :     /* A buffer with the following structure is expected.
     515             :      * int32_t status of the request (required)
     516             :      * message (zero or more)
     517             :      *
     518             :      * A message consists of:
     519             :      * int32_t type of the message
     520             :      * int32_t length of the following data
     521             :      * uint8_t[len] data
     522             :      */
     523             : 
     524           0 :     p=0;
     525           0 :     SAFEALIGN_COPY_INT32(&msg_status, buf+p, &p);
     526             : 
     527           0 :     while (p < len) {
     528           0 :         skip = false;
     529           0 :         SAFEALIGN_COPY_INT32(&msg_type, buf+p, &p);
     530           0 :         SAFEALIGN_COPY_INT32(&msg_len, buf+p, &p);
     531             : 
     532           0 :         DEBUG(SSSDBG_TRACE_LIBS, "child response [%d][%d][%d].\n",
     533             :               msg_status, msg_type, msg_len);
     534             : 
     535           0 :         if (msg_len > len - p) {
     536           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "message format error [%d] > [%zu].\n",
     537             :                   msg_len, len - p);
     538           0 :             return EINVAL;
     539             :         }
     540             : 
     541             :         /* We need to save the name of the credential cache file. To find it
     542             :          * we check if the data part of a message starts with
     543             :          * CCACHE_ENV_NAME"=". pref_len also counts the trailing '=' because
     544             :          * sizeof() counts the trailing '\0' of a string. */
     545           0 :         pref_len = sizeof(CCACHE_ENV_NAME);
     546           0 :         if ((msg_type == SSS_PAM_ENV_ITEM) &&
     547           0 :             (msg_len > pref_len) &&
     548           0 :             (strncmp((const char *) &buf[p], CCACHE_ENV_NAME"=", pref_len) == 0)) {
     549           0 :             ccname = (char *) &buf[p+pref_len];
     550           0 :             ccname_len = msg_len-pref_len;
     551             :         }
     552             : 
     553           0 :         if (msg_type == SSS_KRB5_INFO_TGT_LIFETIME &&
     554           0 :             msg_len == 4*sizeof(int64_t)) {
     555           0 :             SAFEALIGN_COPY_INT64(&time_data, buf+p, NULL);
     556           0 :             tgtt.authtime = int64_to_time_t(time_data);
     557           0 :             SAFEALIGN_COPY_INT64(&time_data, buf+p+sizeof(int64_t), NULL);
     558           0 :             tgtt.starttime = int64_to_time_t(time_data);
     559           0 :             SAFEALIGN_COPY_INT64(&time_data, buf+p+2*sizeof(int64_t), NULL);
     560           0 :             tgtt.endtime = int64_to_time_t(time_data);
     561           0 :             SAFEALIGN_COPY_INT64(&time_data, buf+p+3*sizeof(int64_t), NULL);
     562           0 :             tgtt.renew_till = int64_to_time_t(time_data);
     563           0 :             DEBUG(SSSDBG_TRACE_LIBS, "TGT times are [%ld][%ld][%ld][%ld].\n",
     564             :                   tgtt.authtime, tgtt.starttime, tgtt.endtime, tgtt.renew_till);
     565             :         }
     566             : 
     567           0 :         if (msg_type == SSS_KRB5_INFO_UPN) {
     568           0 :             upn = (char *) buf + p;
     569           0 :             upn_len = msg_len;
     570             :         }
     571             : 
     572           0 :         if (msg_type == SSS_PAM_USER_INFO) {
     573           0 :             SAFEALIGN_COPY_UINT32(&msg_subtype, buf + p, NULL);
     574           0 :             if (msg_subtype == SSS_PAM_USER_INFO_EXPIRE_WARN) {
     575           0 :                 SAFEALIGN_COPY_UINT32(&expiration,
     576             :                                       buf + p + sizeof(uint32_t), NULL);
     577           0 :                 if (pwd_exp_warning > 0 &&
     578           0 :                     difftime(pwd_exp_warning, expiration) < 0.0) {
     579           0 :                     skip = true;
     580             :                 }
     581             :             }
     582             :         }
     583             : 
     584           0 :         if (msg_type == SSS_OTP) {
     585           0 :             otp = true;
     586           0 :             skip = true;
     587             :         }
     588             : 
     589           0 :         if (!skip) {
     590           0 :             ret = pam_add_response(pd, msg_type, msg_len, &buf[p]);
     591           0 :             if (ret != EOK) {
     592             :                 /* This is not a fatal error */
     593           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
     594             :             }
     595             :         }
     596             : 
     597           0 :         p += msg_len;
     598             : 
     599           0 :         if ((p < len) && (p + 2*sizeof(int32_t) > len)) {
     600           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     601             :                   "The remainder of the message is too short.\n");
     602           0 :             return EINVAL;
     603             :         }
     604             :     }
     605             : 
     606           0 :     res = talloc_zero(mem_ctx, struct krb5_child_response);
     607           0 :     if (!res) return ENOMEM;
     608             : 
     609           0 :     res->otp = otp;
     610           0 :     res->msg_status = msg_status;
     611           0 :     memcpy(&res->tgtt, &tgtt, sizeof(tgtt));
     612             : 
     613           0 :     if (ccname) {
     614           0 :         res->ccname = talloc_strndup(res, ccname, ccname_len);
     615           0 :         if (res->ccname == NULL) {
     616           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
     617           0 :             talloc_free(res);
     618           0 :             return ENOMEM;
     619             :         }
     620             :     }
     621             : 
     622           0 :     if (upn != NULL) {
     623           0 :         res->correct_upn = talloc_strndup(res, upn, upn_len);
     624           0 :         if (res->correct_upn == NULL) {
     625           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "talloc_strndup failed.\n");
     626           0 :             talloc_free(res);
     627           0 :             return ENOMEM;
     628             :         }
     629             :     }
     630             : 
     631           0 :     *_res = res;
     632           0 :     return EOK;
     633             : }

Generated by: LCOV version 1.10