LCOV - code coverage report
Current view: top level - third_party/pam_wrapper - libpamtest.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 89 167 53.3 %
Date: 2024-04-21 15:09:00 Functions: 5 9 55.6 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2015 Andreas Schneider <asn@samba.org>
       3             :  * Copyright (c) 2015 Jakub Hrozek <jakub.hrozek@posteo.se>
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #include "config.h"
      20             : 
      21             : #include <stdlib.h>
      22             : #include <string.h>
      23             : #include <stdbool.h>
      24             : 
      25             : #include "libpamtest.h"
      26             : 
      27             : #define MIN(a,b) ((a) < (b) ? (a) : (b))
      28             : 
      29         256 : static enum pamtest_err run_test_case(pam_handle_t *ph,
      30             :                                       struct pam_testcase *tc)
      31             : {
      32         256 :         switch (tc->pam_operation) {
      33         238 :         case PAMTEST_AUTHENTICATE:
      34         238 :                 tc->op_rv = pam_authenticate(ph, tc->flags);
      35         238 :                 return PAMTEST_ERR_OK;
      36           2 :         case PAMTEST_SETCRED:
      37           2 :                 tc->op_rv = pam_setcred(ph, tc->flags);
      38           2 :                 return PAMTEST_ERR_OK;
      39           0 :         case PAMTEST_ACCOUNT:
      40           0 :                 tc->op_rv = pam_acct_mgmt(ph, tc->flags);
      41           0 :                 return PAMTEST_ERR_OK;
      42           0 :         case PAMTEST_OPEN_SESSION:
      43           0 :                 tc->op_rv = pam_open_session(ph, tc->flags);
      44           0 :                 return PAMTEST_ERR_OK;
      45           0 :         case PAMTEST_CLOSE_SESSION:
      46           0 :                 tc->op_rv = pam_close_session(ph, tc->flags);
      47           0 :                 return PAMTEST_ERR_OK;
      48          12 :         case PAMTEST_CHAUTHTOK:
      49          12 :                 tc->op_rv = pam_chauthtok(ph, tc->flags);
      50          12 :                 return PAMTEST_ERR_OK;
      51           2 :         case PAMTEST_GETENVLIST:
      52           2 :                 tc->case_out.envlist = pam_getenvlist(ph);
      53           2 :                 return PAMTEST_ERR_OK;
      54           2 :         case PAMTEST_KEEPHANDLE:
      55           2 :                 tc->case_out.ph = ph;
      56           2 :                 return PAMTEST_ERR_KEEPHANDLE;
      57           0 :         default:
      58           0 :                 return PAMTEST_ERR_OP;
      59             :         }
      60             : 
      61             :         return PAMTEST_ERR_OP;
      62             : }
      63             : 
      64         252 : enum pamtest_err _pamtest_conv(const char *service,
      65             :                                const char *user,
      66             :                                pam_conv_fn conv_fn,
      67             :                                void *conv_userdata,
      68             :                                struct pam_testcase test_cases[],
      69             :                                size_t num_test_cases,
      70             :                                pam_handle_t *pam_handle)
      71             : {
      72             :         int rv;
      73             :         pam_handle_t *ph;
      74             :         struct pam_conv conv;
      75             :         size_t tcindex;
      76         252 :         struct pam_testcase *tc = NULL;
      77         252 :         bool call_pam_end = true;
      78             : 
      79         252 :         conv.conv = conv_fn;
      80         252 :         conv.appdata_ptr = conv_userdata;
      81             : 
      82         252 :         if (test_cases == NULL) {
      83           0 :                 return PAMTEST_ERR_INTERNAL;
      84             :         }
      85             : 
      86         252 :         if (pam_handle == NULL) {
      87         250 :                 rv = pam_start(service, user, &conv, &ph);
      88         250 :                 if (rv != PAM_SUCCESS) {
      89           0 :                         return PAMTEST_ERR_START;
      90             :                 }
      91             :         } else {
      92           2 :                 ph = pam_handle;
      93             :         }
      94             : 
      95         508 :         for (tcindex = 0; tcindex < num_test_cases; tcindex++) {
      96         256 :                 tc = &test_cases[tcindex];
      97             : 
      98         256 :                 rv = run_test_case(ph, tc);
      99         256 :                 if (rv == PAMTEST_ERR_KEEPHANDLE) {
     100           2 :                         call_pam_end = false;
     101           2 :                         continue;
     102         254 :                 } else if (rv != PAMTEST_ERR_OK) {
     103           0 :                         return PAMTEST_ERR_INTERNAL;
     104             :                 }
     105             : 
     106         254 :                 if (tc->op_rv != tc->expected_rv) {
     107           0 :                         break;
     108             :                 }
     109             :         }
     110             : 
     111         252 :         if (call_pam_end == true && tc != NULL) {
     112         250 :                 rv = pam_end(ph, tc->op_rv);
     113         250 :                 if (rv != PAM_SUCCESS) {
     114           0 :                         return PAMTEST_ERR_END;
     115             :                 }
     116             :         }
     117             : 
     118         252 :         if (tcindex < num_test_cases) {
     119           0 :                 return PAMTEST_ERR_CASE;
     120             :         }
     121             : 
     122         252 :         return PAMTEST_ERR_OK;
     123             : }
     124             : 
     125           0 : void pamtest_free_env(char **envlist)
     126             : {
     127             :         size_t i;
     128             : 
     129           0 :         if (envlist == NULL) {
     130           0 :                 return;
     131             :         }
     132             : 
     133           0 :         for (i = 0; envlist[i] != NULL; i++) {
     134           0 :                 free(envlist[i]);
     135             :         }
     136           0 :         free(envlist);
     137             : }
     138             : 
     139             : const struct pam_testcase *
     140           0 : _pamtest_failed_case(struct pam_testcase *test_cases,
     141             :                      size_t num_test_cases)
     142             : {
     143             :         size_t tcindex;
     144             : 
     145           0 :         for (tcindex = 0; tcindex < num_test_cases; tcindex++) {
     146           0 :                 const struct pam_testcase *tc = &test_cases[tcindex];
     147             : 
     148           0 :                 if (tc->expected_rv != tc->op_rv) {
     149           0 :                         return tc;
     150             :                 }
     151             :         }
     152             : 
     153             :         /* Nothing failed */
     154           0 :         return NULL;
     155             : }
     156             : 
     157           0 : const char *pamtest_strerror(enum pamtest_err perr)
     158             : {
     159           0 :         switch (perr) {
     160           0 :         case PAMTEST_ERR_OK:
     161           0 :                 return "Success";
     162           0 :         case PAMTEST_ERR_START:
     163           0 :                 return "pam_start failed()";
     164           0 :         case PAMTEST_ERR_CASE:
     165           0 :                 return "Unexpected testcase result";
     166           0 :         case PAMTEST_ERR_OP:
     167           0 :                 return "Could not run a test case";
     168           0 :         case PAMTEST_ERR_END:
     169           0 :                 return "pam_end failed()";
     170           0 :         case PAMTEST_ERR_KEEPHANDLE:
     171             :                 /* Fallthrough */
     172             :         case PAMTEST_ERR_INTERNAL:
     173           0 :                 return "Internal libpamtest error";
     174             :         }
     175             : 
     176           0 :         return "Unknown";
     177             : }
     178             : 
     179             : struct pamtest_conv_ctx {
     180             :         struct pamtest_conv_data *data;
     181             : 
     182             :         size_t echo_off_idx;
     183             :         size_t echo_on_idx;
     184             :         size_t err_idx;
     185             :         size_t info_idx;
     186             : };
     187             : 
     188         326 : static int add_to_reply(struct pam_response *reply, const char *str)
     189             : {
     190             :         size_t len;
     191             : 
     192         326 :         len = strlen(str) + 1;
     193             : 
     194         326 :         reply->resp = calloc(len, sizeof(char));
     195         326 :         if (reply->resp == NULL) {
     196           0 :                 return PAM_BUF_ERR;
     197             :         }
     198             : 
     199         326 :         memcpy(reply->resp, str, len);
     200         326 :         return PAM_SUCCESS;
     201             : }
     202             : 
     203           0 : static void free_reply(struct pam_response *reply, int num_msg)
     204             : {
     205             :         int i;
     206             : 
     207           0 :         if (reply == NULL) {
     208           0 :                 return;
     209             :         }
     210             : 
     211           0 :         for (i = 0; i < num_msg; i++) {
     212           0 :                 free(reply[i].resp);
     213             :         }
     214           0 :         free(reply);
     215             : }
     216             : 
     217         310 : static int pamtest_simple_conv(int num_msg,
     218             :                                const struct pam_message **msgm,
     219             :                                struct pam_response **response,
     220             :                                void *appdata_ptr)
     221             : {
     222         310 :         int i = 0;
     223             :         int ret;
     224         310 :         struct pam_response *reply = NULL;
     225             :         const char *prompt;
     226         310 :         struct pamtest_conv_ctx *cctx = (struct pamtest_conv_ctx *)appdata_ptr;
     227             : 
     228         310 :         if (cctx == NULL) {
     229           0 :                 return PAM_CONV_ERR;
     230             :         }
     231             : 
     232         310 :         if (response) {
     233         310 :                 reply = (struct pam_response *) calloc(num_msg,
     234             :                                                 sizeof(struct pam_response));
     235         310 :                 if (reply == NULL) {
     236           0 :                         return PAM_CONV_ERR;
     237             :                 }
     238             :         }
     239             : 
     240         636 :         for (i=0; i < num_msg; i++) {
     241         326 :                 switch (msgm[i]->msg_style) {
     242         258 :                 case PAM_PROMPT_ECHO_OFF:
     243         258 :                         prompt = (const char *) \
     244         258 :                                    cctx->data->in_echo_off[cctx->echo_off_idx];
     245             : 
     246         258 :                         if (reply != NULL) {
     247         258 :                                 if (prompt != NULL) {
     248         258 :                                         ret = add_to_reply(&reply[i], prompt);
     249         258 :                                         if (ret != PAM_SUCCESS) {
     250           0 :                                                 free_reply(reply, num_msg);
     251           0 :                                                 return ret;
     252             :                                         }
     253             :                                 }
     254             :                         }
     255             : 
     256         258 :                         cctx->echo_off_idx++;
     257         258 :                         break;
     258           0 :                 case PAM_PROMPT_ECHO_ON:
     259           0 :                         prompt = (const char *) \
     260           0 :                                    cctx->data->in_echo_on[cctx->echo_on_idx];
     261           0 :                         if (prompt == NULL) {
     262           0 :                                 free_reply(reply, num_msg);
     263           0 :                                 return PAM_CONV_ERR;
     264             :                         }
     265             : 
     266           0 :                         if (reply != NULL) {
     267           0 :                                 if (prompt != NULL) {
     268           0 :                                         ret = add_to_reply(&reply[i], prompt);
     269           0 :                                         if (ret != PAM_SUCCESS) {
     270           0 :                                                 free_reply(reply, num_msg);
     271           0 :                                                 return ret;
     272             :                                         }
     273             :                                 }
     274             :                         }
     275             : 
     276           0 :                         cctx->echo_on_idx++;
     277           0 :                         break;
     278          52 :                 case PAM_ERROR_MSG:
     279          52 :                         if (reply != NULL) {
     280          52 :                                 ret = add_to_reply(&reply[i], msgm[i]->msg);
     281          52 :                                 if (ret != PAM_SUCCESS) {
     282           0 :                                         free_reply(reply, num_msg);
     283           0 :                                         return ret;
     284             :                                 }
     285             :                         }
     286             : 
     287          52 :                         if (cctx->data->out_err != NULL) {
     288           0 :                                 memcpy(cctx->data->out_err[cctx->err_idx],
     289          52 :                                        msgm[i]->msg,
     290          52 :                                        MIN(strlen(msgm[i]->msg),
     291             :                                            PAM_MAX_MSG_SIZE));
     292          52 :                                 cctx->err_idx++;
     293             :                         }
     294          52 :                         break;
     295          16 :                 case PAM_TEXT_INFO:
     296          16 :                         if (reply != NULL) {
     297          16 :                                 ret = add_to_reply(&reply[i], msgm[i]->msg);
     298          16 :                                 if (ret != PAM_SUCCESS) {
     299           0 :                                         free_reply(reply, num_msg);
     300           0 :                                         return ret;
     301             :                                 }
     302             :                         }
     303             : 
     304          16 :                         if (cctx->data->out_info != NULL) {
     305           0 :                                 memcpy(cctx->data->out_info[cctx->info_idx],
     306          16 :                                        msgm[i]->msg,
     307          16 :                                        MIN(strlen(msgm[i]->msg),
     308             :                                            PAM_MAX_MSG_SIZE));
     309          16 :                                 cctx->info_idx++;
     310             :                         }
     311          16 :                         break;
     312           0 :                 default:
     313           0 :                         continue;
     314             :                 }
     315             :         }
     316             : 
     317         310 :         if (response != NULL) {
     318         310 :                 *response = reply;
     319             :         } else {
     320           0 :                 free(reply);
     321             :         }
     322             : 
     323         310 :         return PAM_SUCCESS;
     324             : }
     325             : 
     326         252 : enum pamtest_err _pamtest(const char *service,
     327             :                           const char *user,
     328             :                           struct pamtest_conv_data *conv_data,
     329             :                           struct pam_testcase test_cases[],
     330             :                           size_t num_test_cases,
     331             :                           pam_handle_t *pam_handle)
     332             : {
     333         252 :         struct pamtest_conv_ctx cctx = {
     334             :                 .data = conv_data,
     335             :         };
     336             : 
     337         252 :         return _pamtest_conv(service, user,
     338             :                              pamtest_simple_conv,
     339             :                              &cctx,
     340             :                              test_cases,
     341             :                              num_test_cases,
     342             :                              pam_handle);
     343             : }

Generated by: LCOV version 1.14