LCOV - code coverage report
Current view: top level - providers/krb5 - krb5_child_handler.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 0 312 0.0 %
Date: 2015-10-19 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             :     int pipefd_to_child[2];
     279             :     int pipefd_from_child[2];
     280             :     pid_t pid;
     281             :     int ret;
     282             :     errno_t err;
     283           0 :     struct handle_child_state *state = tevent_req_data(req,
     284             :                                                      struct handle_child_state);
     285             :     const char *k5c_extra_args[3];
     286             : 
     287           0 :     k5c_extra_args[0] = talloc_asprintf(state, "--fast-ccache-uid=%"SPRIuid, getuid());
     288           0 :     k5c_extra_args[1] = talloc_asprintf(state, "--fast-ccache-gid=%"SPRIgid, getgid());
     289           0 :     k5c_extra_args[2] = NULL;
     290           0 :     if (k5c_extra_args[0] == NULL || k5c_extra_args[1] == NULL) {
     291           0 :         return ENOMEM;
     292             :     }
     293             : 
     294           0 :     ret = pipe(pipefd_from_child);
     295           0 :     if (ret == -1) {
     296           0 :         err = errno;
     297           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     298             :               "pipe failed [%d][%s].\n", errno, strerror(errno));
     299           0 :         return err;
     300             :     }
     301           0 :     ret = pipe(pipefd_to_child);
     302           0 :     if (ret == -1) {
     303           0 :         err = errno;
     304           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     305             :               "pipe failed [%d][%s].\n", errno, strerror(errno));
     306           0 :         return err;
     307             :     }
     308             : 
     309           0 :     pid = fork();
     310             : 
     311           0 :     if (pid == 0) { /* child */
     312           0 :         err = exec_child_ex(state,
     313             :                             pipefd_to_child, pipefd_from_child,
     314           0 :                             KRB5_CHILD, state->kr->krb5_ctx->child_debug_fd,
     315             :                             k5c_extra_args, STDIN_FILENO, STDOUT_FILENO);
     316           0 :         if (err != EOK) {
     317           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Could not exec KRB5 child: [%d][%s].\n",
     318             :                       err, strerror(err));
     319           0 :             return err;
     320             :         }
     321           0 :     } else if (pid > 0) { /* parent */
     322           0 :         state->child_pid = pid;
     323           0 :         state->io->read_from_child_fd = pipefd_from_child[0];
     324           0 :         close(pipefd_from_child[1]);
     325           0 :         state->io->write_to_child_fd = pipefd_to_child[1];
     326           0 :         close(pipefd_to_child[0]);
     327           0 :         sss_fd_nonblocking(state->io->read_from_child_fd);
     328           0 :         sss_fd_nonblocking(state->io->write_to_child_fd);
     329             : 
     330           0 :         ret = child_handler_setup(state->ev, pid, NULL, NULL, NULL);
     331           0 :         if (ret != EOK) {
     332           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     333             :                   "Could not set up child signal handler\n");
     334           0 :             return ret;
     335             :         }
     336             : 
     337           0 :         err = activate_child_timeout_handler(req, state->ev,
     338           0 :                   dp_opt_get_int(state->kr->krb5_ctx->opts, KRB5_AUTH_TIMEOUT));
     339           0 :         if (err != EOK) {
     340           0 :             DEBUG(SSSDBG_CRIT_FAILURE,
     341             :                   "activate_child_timeout_handler failed.\n");
     342             :         }
     343             : 
     344             :     } else { /* error */
     345           0 :         err = errno;
     346           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     347             :               "fork failed [%d][%s].\n", errno, strerror(errno));
     348           0 :         return err;
     349             :     }
     350             : 
     351           0 :     return EOK;
     352             : }
     353             : 
     354             : static void handle_child_step(struct tevent_req *subreq);
     355             : static void handle_child_done(struct tevent_req *subreq);
     356             : 
     357           0 : struct tevent_req *handle_child_send(TALLOC_CTX *mem_ctx,
     358             :                                      struct tevent_context *ev,
     359             :                                      struct krb5child_req *kr)
     360             : {
     361             :     struct tevent_req *req, *subreq;
     362             :     struct handle_child_state *state;
     363             :     int ret;
     364           0 :     struct io_buffer *buf = NULL;
     365             : 
     366           0 :     req = tevent_req_create(mem_ctx, &state, struct handle_child_state);
     367           0 :     if (req == NULL) {
     368           0 :         return NULL;
     369             :     }
     370             : 
     371           0 :     state->ev = ev;
     372           0 :     state->kr = kr;
     373           0 :     state->buf = NULL;
     374           0 :     state->len = 0;
     375           0 :     state->child_pid = -1;
     376           0 :     state->timeout_handler = NULL;
     377             : 
     378           0 :     state->io = talloc(state, struct child_io_fds);
     379           0 :     if (state->io == NULL) {
     380           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     381           0 :         ret = ENOMEM;
     382           0 :         goto fail;
     383             :     }
     384           0 :     state->io->write_to_child_fd = -1;
     385           0 :     state->io->read_from_child_fd = -1;
     386           0 :     talloc_set_destructor((void *) state->io, child_io_destructor);
     387             : 
     388           0 :     ret = create_send_buffer(kr, &buf);
     389           0 :     if (ret != EOK) {
     390           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "create_send_buffer failed.\n");
     391           0 :         goto fail;
     392             :     }
     393             : 
     394           0 :     ret = fork_child(req);
     395           0 :     if (ret != EOK) {
     396           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "fork_child failed.\n");
     397           0 :         goto fail;
     398             :     }
     399             : 
     400           0 :     subreq = write_pipe_send(state, ev, buf->data, buf->size,
     401           0 :                              state->io->write_to_child_fd);
     402           0 :     if (!subreq) {
     403           0 :         ret = ENOMEM;
     404           0 :         goto fail;
     405             :     }
     406           0 :     tevent_req_set_callback(subreq, handle_child_step, req);
     407             : 
     408           0 :     return req;
     409             : 
     410             : fail:
     411           0 :     tevent_req_error(req, ret);
     412           0 :     tevent_req_post(req, ev);
     413           0 :     return req;
     414             : }
     415             : 
     416           0 : static void handle_child_step(struct tevent_req *subreq)
     417             : {
     418           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     419             :                                                       struct tevent_req);
     420           0 :     struct handle_child_state *state = tevent_req_data(req,
     421             :                                                     struct handle_child_state);
     422             :     int ret;
     423             : 
     424           0 :     ret = write_pipe_recv(subreq);
     425           0 :     talloc_zfree(subreq);
     426           0 :     if (ret != EOK) {
     427           0 :         tevent_req_error(req, ret);
     428           0 :         return;
     429             :     }
     430             : 
     431           0 :     close(state->io->write_to_child_fd);
     432           0 :     state->io->write_to_child_fd = -1;
     433             : 
     434           0 :     subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
     435           0 :     if (!subreq) {
     436           0 :         tevent_req_error(req, ENOMEM);
     437           0 :         return;
     438             :     }
     439           0 :     tevent_req_set_callback(subreq, handle_child_done, req);
     440             : }
     441             : 
     442           0 : static void handle_child_done(struct tevent_req *subreq)
     443             : {
     444           0 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     445             :                                                       struct tevent_req);
     446           0 :     struct handle_child_state *state = tevent_req_data(req,
     447             :                                                     struct handle_child_state);
     448             :     int ret;
     449             : 
     450           0 :     talloc_zfree(state->timeout_handler);
     451             : 
     452           0 :     ret = read_pipe_recv(subreq, state, &state->buf, &state->len);
     453           0 :     talloc_zfree(subreq);
     454           0 :     if (ret != EOK) {
     455           0 :         tevent_req_error(req, ret);
     456           0 :         return;
     457             :     }
     458             : 
     459           0 :     close(state->io->read_from_child_fd);
     460           0 :     state->io->read_from_child_fd = -1;
     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