LCOV - code coverage report
Current view: top level - responder/pam - pamsrv_p11.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 171 285 60.0 %
Date: 2016-06-29 Functions: 8 10 80.0 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    PAM Responder - certificate realted requests
       5             : 
       6             :    Copyright (C) Sumit Bose <sbose@redhat.com> 2015
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include <time.h>
      23             : 
      24             : #include "util/util.h"
      25             : #include "providers/data_provider.h"
      26             : #include "util/child_common.h"
      27             : #include "util/strtonum.h"
      28             : #include "responder/pam/pamsrv.h"
      29             : 
      30             : 
      31             : #ifndef SSSD_LIBEXEC_PATH
      32             : #error "SSSD_LIBEXEC_PATH not defined"
      33             : #endif  /* SSSD_LIBEXEC_PATH */
      34             : 
      35             : #define P11_CHILD_LOG_FILE "p11_child"
      36             : #define P11_CHILD_PATH SSSD_LIBEXEC_PATH"/p11_child"
      37             : 
      38           0 : errno_t p11_child_init(struct pam_ctx *pctx)
      39             : {
      40           0 :     return child_debug_init(P11_CHILD_LOG_FILE, &pctx->p11_child_debug_fd);
      41             : }
      42             : 
      43          77 : bool may_do_cert_auth(struct pam_ctx *pctx, struct pam_data *pd)
      44             : {
      45             :     size_t c;
      46          77 :     const char *sc_services[] = { "login", "su", "su-l", "gdm-smartcard",
      47             :                                   "gdm-password", "kdm", "sudo", "sudo-i",
      48             :                                   "gnome-screensaver", NULL };
      49          77 :     if (!pctx->cert_auth) {
      50          59 :         return false;
      51             :     }
      52             : 
      53          18 :     if (pd->cmd != SSS_PAM_PREAUTH && pd->cmd != SSS_PAM_AUTHENTICATE) {
      54           0 :         return false;
      55             :     }
      56             : 
      57          18 :     if (pd->cmd == SSS_PAM_AUTHENTICATE
      58           4 :            && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_PIN
      59           0 :            && sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_SC_KEYPAD) {
      60           0 :         return false;
      61             :     }
      62             : 
      63             :     /* TODO: make services configurable */
      64          18 :     if (pd->service == NULL || *pd->service == '\0') {
      65           0 :         return false;
      66             :     }
      67          18 :     for (c = 0; sc_services[c] != NULL; c++) {
      68          18 :         if (strcmp(pd->service, sc_services[c]) == 0) {
      69          18 :             break;
      70             :         }
      71             :     }
      72          18 :     if  (sc_services[c] == NULL) {
      73           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
      74             :               "Smartcard authentication for service [%s] not supported.\n",
      75             :               pd->service);
      76           0 :         return false;
      77             :     }
      78             : 
      79          18 :     return true;
      80             : }
      81             : 
      82           2 : static errno_t get_p11_child_write_buffer(TALLOC_CTX *mem_ctx,
      83             :                                           struct pam_data *pd,
      84             :                                           uint8_t **_buf, size_t *_len)
      85             : {
      86             :     int ret;
      87             :     uint8_t *buf;
      88             :     size_t len;
      89           2 :     const char *pin = NULL;
      90             : 
      91           2 :     if (pd == NULL || pd->authtok == NULL) {
      92           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing authtok.\n");
      93           0 :         return EINVAL;
      94             :     }
      95             : 
      96           2 :     switch (sss_authtok_get_type(pd->authtok)) {
      97             :     case SSS_AUTHTOK_TYPE_SC_PIN:
      98           2 :         ret = sss_authtok_get_sc_pin(pd->authtok, &pin, &len);
      99           2 :         if (ret != EOK) {
     100           0 :             DEBUG(SSSDBG_OP_FAILURE, "sss_authtok_get_sc_pin failed.\n");
     101           0 :             return ret;
     102             :         }
     103           2 :         if (pin == NULL || len == 0) {
     104           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Missing PIN.\n");
     105           0 :             return EINVAL;
     106             :         }
     107             : 
     108           2 :         buf = talloc_size(mem_ctx, len);
     109           2 :         if (buf == NULL) {
     110           0 :             DEBUG(SSSDBG_OP_FAILURE, "talloc_size failed.\n");
     111           0 :             return ENOMEM;
     112             :         }
     113             : 
     114           2 :         safealign_memcpy(buf, pin, len, NULL);
     115             : 
     116           2 :         break;
     117             :     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
     118             :         /* Nothing to send */
     119           0 :         len = 0;
     120           0 :         buf = NULL;
     121           0 :         break;
     122             :     default:
     123           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unsupported authtok type [%d].\n",
     124             :                                    sss_authtok_get_type(pd->authtok));
     125           0 :         return EINVAL;
     126             :     }
     127             : 
     128           2 :     *_len = len;
     129           2 :     *_buf = buf;
     130             : 
     131           2 :     return EOK;
     132             : }
     133             : 
     134           9 : static errno_t parse_p11_child_response(TALLOC_CTX *mem_ctx, uint8_t *buf,
     135             :                                         ssize_t buf_len, char **_cert,
     136             :                                         char **_token_name)
     137             : {
     138             :     int ret;
     139           9 :     TALLOC_CTX *tmp_ctx = NULL;
     140             :     uint8_t *p;
     141             :     uint8_t *pn;
     142           9 :     char *cert = NULL;
     143           9 :     char *token_name = NULL;
     144             : 
     145           9 :     if (buf_len < 0) {
     146           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     147             :               "Error occurred while reading data from p11_child.\n");
     148           0 :         return EIO;
     149             :     }
     150             : 
     151           9 :     if (buf_len == 0) {
     152           2 :         DEBUG(SSSDBG_TRACE_LIBS, "No certificate found.\n");
     153           2 :         ret = EOK;
     154           2 :         goto done;
     155             :     }
     156             : 
     157           7 :     p = memchr(buf, '\n', buf_len);
     158           7 :     if (p == NULL) {
     159           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing new-line in p11_child response.\n");
     160           0 :         return EINVAL;
     161             :     }
     162           7 :     if (p == buf) {
     163           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing counter in p11_child response.\n");
     164           0 :         return EINVAL;
     165             :     }
     166             : 
     167           7 :     tmp_ctx = talloc_new(NULL);
     168           7 :     if (tmp_ctx == NULL) {
     169           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_new failed.\n");
     170           0 :         return ENOMEM;
     171             :     }
     172             : 
     173           7 :     token_name = talloc_strndup(tmp_ctx, (char*) buf, (p - buf));
     174           7 :     if (token_name == NULL) {
     175           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
     176           0 :         ret = ENOMEM;
     177           0 :         goto done;
     178             :     }
     179             : 
     180           7 :     p++;
     181           7 :     pn = memchr(p, '\n', buf_len - (p - buf));
     182           7 :     if (pn == NULL) {
     183           0 :         DEBUG(SSSDBG_OP_FAILURE,
     184             :               "Missing new-line in p11_child response.\n");
     185           0 :         ret = EINVAL;
     186           0 :         goto done;
     187             :     }
     188             : 
     189           7 :     if (pn == p) {
     190           0 :         DEBUG(SSSDBG_OP_FAILURE, "Missing cert in p11_child response.\n");
     191           0 :         ret = EINVAL;
     192           0 :         goto done;
     193             :     }
     194             : 
     195           7 :     cert = talloc_strndup(tmp_ctx, (char *) p, (pn - p));
     196           7 :     if(cert == NULL) {
     197           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_strndup failed.\n");
     198           0 :         ret = ENOMEM;
     199           0 :         goto done;
     200             :     }
     201           7 :     DEBUG(SSSDBG_TRACE_ALL, "Found cert [%s].\n", cert);
     202             : 
     203           7 :     ret = EOK;
     204             : 
     205             : done:
     206           9 :     if (ret == EOK) {
     207           9 :         *_token_name = talloc_steal(mem_ctx, token_name);
     208           9 :         *_cert = talloc_steal(mem_ctx, cert);
     209             :     }
     210             : 
     211           9 :     talloc_free(tmp_ctx);
     212             : 
     213           9 :     return ret;
     214             : }
     215             : 
     216             : struct pam_check_cert_state {
     217             :     int child_status;
     218             :     struct sss_child_ctx_old *child_ctx;
     219             :     struct tevent_timer *timeout_handler;
     220             :     struct tevent_context *ev;
     221             : 
     222             :     struct child_io_fds *io;
     223             :     char *cert;
     224             :     char *token_name;
     225             : };
     226             : 
     227             : static void p11_child_write_done(struct tevent_req *subreq);
     228             : static void p11_child_done(struct tevent_req *subreq);
     229             : static void p11_child_timeout(struct tevent_context *ev,
     230             :                               struct tevent_timer *te,
     231             :                               struct timeval tv, void *pvt);
     232             : 
     233           9 : struct tevent_req *pam_check_cert_send(TALLOC_CTX *mem_ctx,
     234             :                                        struct tevent_context *ev,
     235             :                                        int child_debug_fd,
     236             :                                        const char *nss_db,
     237             :                                        time_t timeout,
     238             :                                        const char *verify_opts,
     239             :                                        struct pam_data *pd)
     240             : {
     241             :     errno_t ret;
     242             :     struct tevent_req *req;
     243             :     struct tevent_req *subreq;
     244             :     struct pam_check_cert_state *state;
     245             :     pid_t child_pid;
     246             :     struct timeval tv;
     247           9 :     int pipefd_to_child[2] = PIPE_INIT;
     248           9 :     int pipefd_from_child[2] = PIPE_INIT;
     249           9 :     const char *extra_args[7] = { NULL };
     250           9 :     uint8_t *write_buf = NULL;
     251           9 :     size_t write_buf_len = 0;
     252             :     size_t arg_c;
     253             : 
     254           9 :     req = tevent_req_create(mem_ctx, &state, struct pam_check_cert_state);
     255           9 :     if (req == NULL) {
     256           0 :         return NULL;
     257             :     }
     258             : 
     259           9 :     if (nss_db == NULL) {
     260           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing NSS DB.\n");
     261           0 :         ret = EINVAL;
     262           0 :         goto done;
     263             :     }
     264             : 
     265             :     /* extra_args are added in revers order */
     266           9 :     arg_c = 0;
     267           9 :     extra_args[arg_c++] = nss_db;
     268           9 :     extra_args[arg_c++] = "--nssdb";
     269           9 :     if (verify_opts != NULL) {
     270           9 :         extra_args[arg_c++] = verify_opts;
     271           9 :         extra_args[arg_c++] = "--verify";
     272             :     }
     273           9 :     if (pd->cmd == SSS_PAM_AUTHENTICATE) {
     274           2 :         extra_args[arg_c++] = "--auth";
     275           2 :         switch (sss_authtok_get_type(pd->authtok)) {
     276             :         case SSS_AUTHTOK_TYPE_SC_PIN:
     277           2 :             extra_args[arg_c++] = "--pin";
     278           2 :             break;
     279             :         case SSS_AUTHTOK_TYPE_SC_KEYPAD:
     280           0 :             extra_args[arg_c++] = "--keypad";
     281           0 :             break;
     282             :         default:
     283           0 :             DEBUG(SSSDBG_OP_FAILURE, "Unsupported authtok type.\n");
     284           0 :             ret = EINVAL;
     285           0 :             goto done;
     286             :         }
     287           7 :     } else if (pd->cmd == SSS_PAM_PREAUTH) {
     288           7 :         extra_args[arg_c++] = "--pre";
     289             :     } else {
     290           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Unexpected PAM command [%d}.\n", pd->cmd);
     291           0 :         ret = EINVAL;
     292           0 :         goto done;
     293             :     }
     294             : 
     295           9 :     state->ev = ev;
     296           9 :     state->child_status = EFAULT;
     297           9 :     state->cert = NULL;
     298           9 :     state->token_name = NULL;
     299           9 :     state->io = talloc(state, struct child_io_fds);
     300           9 :     if (state->io == NULL) {
     301           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "talloc failed.\n");
     302           0 :         ret = ENOMEM;
     303           0 :         goto done;
     304             :     }
     305           9 :     state->io->write_to_child_fd = -1;
     306           9 :     state->io->read_from_child_fd = -1;
     307           9 :     talloc_set_destructor((void *) state->io, child_io_destructor);
     308             : 
     309           9 :     ret = pipe(pipefd_from_child);
     310           9 :     if (ret == -1) {
     311           0 :         ret = errno;
     312           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     313             :               "pipe failed [%d][%s].\n", ret, strerror(ret));
     314           0 :         goto done;
     315             :     }
     316           9 :     ret = pipe(pipefd_to_child);
     317           9 :     if (ret == -1) {
     318           0 :         ret = errno;
     319           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     320             :               "pipe failed [%d][%s].\n", ret, strerror(ret));
     321           0 :         goto done;
     322             :     }
     323             : 
     324           9 :     if (child_debug_fd == -1) {
     325           0 :         child_debug_fd = STDERR_FILENO;
     326             :     }
     327             : 
     328           9 :     child_pid = fork();
     329           9 :     if (child_pid == 0) { /* child */
     330           0 :         exec_child_ex(state, pipefd_to_child, pipefd_from_child,
     331             :                       P11_CHILD_PATH, child_debug_fd, extra_args, false,
     332             :                       STDIN_FILENO, STDOUT_FILENO);
     333             : 
     334             :         /* We should never get here */
     335           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "BUG: Could not exec p11 child\n");
     336           9 :     } else if (child_pid > 0) { /* parent */
     337             : 
     338           9 :         state->io->read_from_child_fd = pipefd_from_child[0];
     339           9 :         PIPE_FD_CLOSE(pipefd_from_child[1]);
     340           9 :         sss_fd_nonblocking(state->io->read_from_child_fd);
     341             : 
     342           9 :         state->io->write_to_child_fd = pipefd_to_child[1];
     343           9 :         PIPE_FD_CLOSE(pipefd_to_child[0]);
     344           9 :         sss_fd_nonblocking(state->io->write_to_child_fd);
     345             : 
     346             :         /* Set up SIGCHLD handler */
     347           9 :         ret = child_handler_setup(ev, child_pid, NULL, NULL, &state->child_ctx);
     348           9 :         if (ret != EOK) {
     349           0 :             DEBUG(SSSDBG_OP_FAILURE, "Could not set up child handlers [%d]: %s\n",
     350             :                 ret, sss_strerror(ret));
     351           0 :             ret = ERR_P11_CHILD;
     352           0 :             goto done;
     353             :         }
     354             : 
     355             :         /* Set up timeout handler */
     356           9 :         tv = tevent_timeval_current_ofs(timeout, 0);
     357           9 :         state->timeout_handler = tevent_add_timer(ev, req, tv,
     358             :                                                   p11_child_timeout, req);
     359           9 :         if(state->timeout_handler == NULL) {
     360           0 :             ret = ERR_P11_CHILD;
     361           0 :             goto done;
     362             :         }
     363             : 
     364           9 :         if (pd->cmd == SSS_PAM_AUTHENTICATE) {
     365           2 :             ret = get_p11_child_write_buffer(state, pd, &write_buf,
     366             :                                              &write_buf_len);
     367           2 :             if (ret != EOK) {
     368           0 :                 DEBUG(SSSDBG_OP_FAILURE,
     369             :                       "get_p11_child_write_buffer failed.\n");
     370           0 :                 goto done;
     371             :             }
     372             :         }
     373             : 
     374           9 :         if (write_buf_len != 0) {
     375           2 :             subreq = write_pipe_send(state, ev, write_buf, write_buf_len,
     376           2 :                                      state->io->write_to_child_fd);
     377           2 :             if (subreq == NULL) {
     378           0 :                 DEBUG(SSSDBG_OP_FAILURE, "write_pipe_send failed.\n");
     379           0 :                 ret = ERR_P11_CHILD;
     380           0 :                 goto done;
     381             :             }
     382           2 :             tevent_req_set_callback(subreq, p11_child_write_done, req);
     383             :         } else {
     384           7 :             subreq = read_pipe_send(state, ev, state->io->read_from_child_fd);
     385           7 :             if (subreq == NULL) {
     386           0 :                 DEBUG(SSSDBG_OP_FAILURE, "read_pipe_send failed.\n");
     387           0 :                 ret = ERR_P11_CHILD;
     388           0 :                 goto done;
     389             :             }
     390           7 :             tevent_req_set_callback(subreq, p11_child_done, req);
     391             :         }
     392             : 
     393             :         /* Now either wait for the timeout to fire or the child
     394             :          * to finish
     395             :          */
     396             :     } else { /* error */
     397           0 :         ret = errno;
     398           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "fork failed [%d][%s].\n",
     399             :                                    ret, sss_strerror(ret));
     400           0 :         goto done;
     401             :     }
     402             : 
     403           9 :     ret = EOK;
     404             : 
     405             : done:
     406           9 :     if (ret != EOK) {
     407           0 :         PIPE_CLOSE(pipefd_from_child);
     408           0 :         PIPE_CLOSE(pipefd_to_child);
     409           0 :         tevent_req_error(req, ret);
     410           0 :         tevent_req_post(req, ev);
     411             :     }
     412           9 :     return req;
     413             : }
     414             : 
     415           2 : static void p11_child_write_done(struct tevent_req *subreq)
     416             : {
     417           2 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     418             :                                                       struct tevent_req);
     419           2 :     struct pam_check_cert_state *state = tevent_req_data(req,
     420             :                                                    struct pam_check_cert_state);
     421             :     int ret;
     422             : 
     423           2 :     ret = write_pipe_recv(subreq);
     424           2 :     talloc_zfree(subreq);
     425           2 :     if (ret != EOK) {
     426           0 :         tevent_req_error(req, ret);
     427           0 :         return;
     428             :     }
     429             : 
     430           2 :     PIPE_FD_CLOSE(state->io->write_to_child_fd);
     431             : 
     432           2 :     subreq = read_pipe_send(state, state->ev, state->io->read_from_child_fd);
     433           2 :     if (subreq == NULL) {
     434           0 :         tevent_req_error(req, ENOMEM);
     435           0 :         return;
     436             :     }
     437           2 :     tevent_req_set_callback(subreq, p11_child_done, req);
     438             : }
     439             : 
     440           9 : static void p11_child_done(struct tevent_req *subreq)
     441             : {
     442             :     uint8_t *buf;
     443             :     ssize_t buf_len;
     444           9 :     struct tevent_req *req = tevent_req_callback_data(subreq,
     445             :                                                       struct tevent_req);
     446           9 :     struct pam_check_cert_state *state = tevent_req_data(req,
     447             :                                                    struct pam_check_cert_state);
     448             :     int ret;
     449             : 
     450           9 :     talloc_zfree(state->timeout_handler);
     451             : 
     452           9 :     ret = read_pipe_recv(subreq, state, &buf, &buf_len);
     453           9 :     talloc_zfree(subreq);
     454           9 :     if (ret != EOK) {
     455           0 :         tevent_req_error(req, ret);
     456           0 :         return;
     457             :     }
     458             : 
     459           9 :     PIPE_FD_CLOSE(state->io->read_from_child_fd);
     460             : 
     461           9 :     ret = parse_p11_child_response(state, buf, buf_len, &state->cert,
     462             :                                    &state->token_name);
     463           9 :     if (ret != EOK) {
     464           0 :         DEBUG(SSSDBG_OP_FAILURE, "parse_p11_child_respose failed.\n");
     465           0 :         tevent_req_error(req, ret);
     466           0 :         return;
     467             :     }
     468             : 
     469           9 :     tevent_req_done(req);
     470           9 :     return;
     471             : }
     472             : 
     473           0 : static void p11_child_timeout(struct tevent_context *ev,
     474             :                               struct tevent_timer *te,
     475             :                               struct timeval tv, void *pvt)
     476             : {
     477           0 :     struct tevent_req *req = talloc_get_type(pvt, struct tevent_req);
     478           0 :     struct pam_check_cert_state *state =
     479           0 :                               tevent_req_data(req, struct pam_check_cert_state);
     480             : 
     481           0 :     DEBUG(SSSDBG_CRIT_FAILURE, "Timeout reached for p11_child.\n");
     482           0 :     child_handler_destroy(state->child_ctx);
     483           0 :     state->child_ctx = NULL;
     484           0 :     state->child_status = ETIMEDOUT;
     485           0 :     tevent_req_error(req, ERR_P11_CHILD);
     486           0 : }
     487             : 
     488           9 : errno_t pam_check_cert_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx,
     489             :                             char **cert, char **token_name)
     490             : {
     491           9 :     struct pam_check_cert_state *state =
     492           9 :                               tevent_req_data(req, struct pam_check_cert_state);
     493             : 
     494           9 :     TEVENT_REQ_RETURN_ON_ERROR(req);
     495             : 
     496           9 :     if (cert != NULL) {
     497           9 :         *cert = talloc_steal(mem_ctx, state->cert);
     498             :     }
     499             : 
     500           9 :     if (token_name != NULL) {
     501           9 :         *token_name = talloc_steal(mem_ctx, state->token_name);
     502             :     }
     503             : 
     504           9 :     return EOK;
     505             : }
     506             : 
     507             : /* The PKCS11_LOGIN_TOKEN_NAME environment variable is e.g. used by the Gnome
     508             :  * Settings Daemon to determine the name of the token used for login */
     509             : #define PKCS11_LOGIN_TOKEN_ENV_NAME "PKCS11_LOGIN_TOKEN_NAME"
     510             : 
     511           2 : errno_t add_pam_cert_response(struct pam_data *pd, const char *user,
     512             :                               const char *token_name)
     513             : {
     514           2 :     uint8_t *msg = NULL;
     515           2 :     char *env = NULL;
     516             :     size_t user_len;
     517             :     size_t msg_len;
     518             :     size_t slot_len;
     519             :     int ret;
     520             : 
     521           2 :     if (user == NULL || token_name == NULL) {
     522           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing mandatory user or slot name.\n");
     523           0 :         return EINVAL;
     524             :     }
     525             : 
     526           2 :     user_len = strlen(user) + 1;
     527           2 :     slot_len = strlen(token_name) + 1;
     528           2 :     msg_len = user_len + slot_len;
     529             : 
     530           2 :     msg = talloc_zero_size(pd, msg_len);
     531           2 :     if (msg == NULL) {
     532           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_zero_size failed.\n");
     533           0 :         return ENOMEM;
     534             :     }
     535             : 
     536           2 :     memcpy(msg, user, user_len);
     537           2 :     memcpy(msg + user_len, token_name, slot_len);
     538             : 
     539           2 :     ret = pam_add_response(pd, SSS_PAM_CERT_INFO, msg_len, msg);
     540           2 :     talloc_free(msg);
     541           2 :     if (ret != EOK) {
     542           0 :         DEBUG(SSSDBG_OP_FAILURE,
     543             :               "pam_add_response failed to add certificate info.\n");
     544           0 :         return ret;
     545             :     }
     546             : 
     547           2 :     env = talloc_asprintf(pd, "%s=%s", PKCS11_LOGIN_TOKEN_ENV_NAME, token_name);
     548           2 :     if (env == NULL) {
     549           0 :         DEBUG(SSSDBG_OP_FAILURE, "talloc_asprintf failed.\n");
     550           0 :         return ENOMEM;
     551             :     }
     552             : 
     553           2 :     ret = pam_add_response(pd, SSS_PAM_ENV_ITEM, strlen(env) + 1,
     554             :                            (uint8_t *)env);
     555           2 :     talloc_free(env);
     556           2 :     if (ret != EOK) {
     557           0 :         DEBUG(SSSDBG_OP_FAILURE,
     558             :               "pam_add_response failed to add environment variable.\n");
     559           0 :         return ret;
     560             :     }
     561             : 
     562           2 :     return ret;
     563             : }

Generated by: LCOV version 1.10