LCOV - code coverage report
Current view: top level - responder/pam - pamsrv_extract.c (source / functions) Hit Total Coverage
Test: .coverage.total Lines: 101 174 58.0 %
Date: 2015-10-19 Functions: 6 8 75.0 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    PAM Responder
       5             : 
       6             :    Copyright (C) Simo Sorce <ssorce@redhat.com>   2009
       7             :    Copyright (C) Sumit Bose <sbose@redhat.com>    2009
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "util/util.h"
      24             : #include "providers/data_provider.h"
      25             : #include "responder/pam/pamsrv.h"
      26             : #include "responder/common/responder_packet.h"
      27             : 
      28             : static int pam_parse_in_data(struct pam_data *pd,
      29             :                              uint8_t *body, size_t blen);
      30             : static int pam_parse_in_data_v2(struct pam_data *pd,
      31             :                                 uint8_t *body, size_t blen);
      32             : static int pam_parse_in_data_v3(struct pam_data *pd,
      33             :                                 uint8_t *body, size_t blen);
      34             : 
      35          47 : errno_t pam_forwarder_parse_data(struct cli_ctx *cctx, struct pam_data *pd)
      36             : {
      37             :     uint8_t *body;
      38             :     size_t blen;
      39             :     errno_t ret;
      40             :     uint32_t terminator;
      41             : 
      42          47 :     sss_packet_get_body(cctx->creq->in, &body, &blen);
      43          47 :     if (blen >= sizeof(uint32_t)) {
      44          47 :         SAFEALIGN_COPY_UINT32(&terminator,
      45             :                               body + blen - sizeof(uint32_t),
      46             :                               NULL);
      47          47 :         if (terminator != SSS_END_OF_PAM_REQUEST) {
      48           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Received data not terminated.\n");
      49           0 :             ret = EINVAL;
      50           0 :             goto done;
      51             :         }
      52             :     }
      53             : 
      54          47 :     switch (cctx->cli_protocol_version->version) {
      55             :         case 1:
      56           0 :             ret = pam_parse_in_data(pd, body, blen);
      57           0 :             break;
      58             :         case 2:
      59           0 :             ret = pam_parse_in_data_v2(pd, body, blen);
      60           0 :             break;
      61             :         case 3:
      62          47 :             ret = pam_parse_in_data_v3(pd, body, blen);
      63          47 :             break;
      64             :         default:
      65           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Illegal protocol version [%d].\n",
      66             :                       cctx->cli_protocol_version->version);
      67           0 :             ret = EINVAL;
      68             :     }
      69          47 :     if (ret != EOK) {
      70           0 :         goto done;
      71             :     }
      72             : 
      73          47 :     if (pd->logon_name != NULL) {
      74          86 :         ret = sss_parse_name_for_domains(pd, cctx->rctx->domains,
      75          43 :                                          cctx->rctx->default_domain,
      76          43 :                                          pd->logon_name,
      77             :                                          &pd->domain, &pd->user);
      78             :     } else {
      79             :         /* Only SSS_PAM_PREAUTH request may have a missing name, e.g. if the
      80             :          * name is determined with the help of a certificate */
      81           4 :         if (pd->cmd == SSS_PAM_PREAUTH
      82           4 :                 && may_do_cert_auth(talloc_get_type(cctx->rctx->pvt_ctx,
      83             :                                                     struct pam_ctx), pd)) {
      84           3 :             ret = EOK;
      85             :         } else {
      86           1 :             DEBUG(SSSDBG_CRIT_FAILURE, "Missing logon name in PAM request.\n");
      87           1 :             ret = ERR_NO_CREDS;
      88           1 :             goto done;
      89             :         }
      90             :     }
      91             : 
      92          46 :     DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
      93             : 
      94             : done:
      95          47 :     return ret;
      96             : }
      97             : 
      98             : static int extract_authtok_v1(struct sss_auth_token *tok,
      99             :                               uint8_t *body, size_t blen, size_t *c);
     100             : static int extract_authtok_v2(struct sss_auth_token *tok,
     101             :                               size_t data_size, uint8_t *body, size_t blen,
     102             :                               size_t *c);
     103             : static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
     104             :                           size_t *c);
     105             : static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
     106             :                             size_t blen, size_t *c);
     107             : 
     108           0 : static int pam_parse_in_data(struct pam_data *pd,
     109             :                              uint8_t *body, size_t blen)
     110             : {
     111             :     size_t start;
     112             :     size_t end;
     113             :     size_t last;
     114             :     int ret;
     115             : 
     116           0 :     last = blen - 1;
     117           0 :     end = 0;
     118             : 
     119             :     /* user name */
     120           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     121           0 :     if (body[end++] != '\0') return EINVAL;
     122           0 :     pd->logon_name = (char *) &body[start];
     123             : 
     124           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     125           0 :     if (body[end++] != '\0') return EINVAL;
     126           0 :     pd->service = (char *) &body[start];
     127             : 
     128           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     129           0 :     if (body[end++] != '\0') return EINVAL;
     130           0 :     pd->tty = (char *) &body[start];
     131             : 
     132           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     133           0 :     if (body[end++] != '\0') return EINVAL;
     134           0 :     pd->ruser = (char *) &body[start];
     135             : 
     136           0 :     for (start = end; end < last; end++) if (body[end] == '\0') break;
     137           0 :     if (body[end++] != '\0') return EINVAL;
     138           0 :     pd->rhost = (char *) &body[start];
     139             : 
     140           0 :     ret = extract_authtok_v1(pd->authtok, body, blen, &end);
     141           0 :     if (ret) {
     142           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid auth token\n");
     143           0 :         return ret;
     144             :     }
     145           0 :     ret = extract_authtok_v1(pd->newauthtok, body, blen, &end);
     146           0 :     if (ret) {
     147           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Invalid new auth token\n");
     148           0 :         return ret;
     149             :     }
     150             : 
     151           0 :     DEBUG_PAM_DATA(SSSDBG_CONF_SETTINGS, pd);
     152             : 
     153           0 :     return EOK;
     154             : }
     155             : 
     156          47 : static int pam_parse_in_data_v2(struct pam_data *pd,
     157             :                                 uint8_t *body, size_t blen)
     158             : {
     159             :     size_t c;
     160             :     uint32_t type;
     161             :     uint32_t size;
     162             :     int ret;
     163             :     uint32_t start;
     164             :     uint32_t terminator;
     165             :     char *requested_domains;
     166             : 
     167          47 :     if (blen < 4*sizeof(uint32_t)+2) {
     168           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
     169           0 :         return EINVAL;
     170             :     }
     171             : 
     172          47 :     SAFEALIGN_COPY_UINT32(&start, body, NULL);
     173          47 :     SAFEALIGN_COPY_UINT32(&terminator, body + blen - sizeof(uint32_t), NULL);
     174             : 
     175          47 :     if (start != SSS_START_OF_PAM_REQUEST
     176          47 :         || terminator != SSS_END_OF_PAM_REQUEST) {
     177           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Received data is invalid.\n");
     178           0 :         return EINVAL;
     179             :     }
     180             : 
     181          47 :     c = sizeof(uint32_t);
     182             :     do {
     183         303 :         SAFEALIGN_COPY_UINT32_CHECK(&type, &body[c], blen, &c);
     184             : 
     185         303 :         if (type == SSS_END_OF_PAM_REQUEST) {
     186          47 :             if (c != blen) return EINVAL;
     187             :         } else {
     188         256 :             SAFEALIGN_COPY_UINT32_CHECK(&size, &body[c], blen, &c);
     189             :             /* the uint32_t end maker SSS_END_OF_PAM_REQUEST does not count to
     190             :              * the remaining buffer */
     191         256 :             if (size > (blen - c - sizeof(uint32_t))) {
     192           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Invalid data size.\n");
     193           0 :                 return EINVAL;
     194             :             }
     195             : 
     196         256 :             switch(type) {
     197             :                 case SSS_PAM_ITEM_USER:
     198          43 :                     ret = extract_string(&pd->logon_name, size, body, blen, &c);
     199          43 :                     if (ret != EOK) return ret;
     200          43 :                     break;
     201             :                 case SSS_PAM_ITEM_SERVICE:
     202          47 :                     ret = extract_string(&pd->service, size, body, blen, &c);
     203          47 :                     if (ret != EOK) return ret;
     204          47 :                     break;
     205             :                 case SSS_PAM_ITEM_TTY:
     206          31 :                     ret = extract_string(&pd->tty, size, body, blen, &c);
     207          31 :                     if (ret != EOK) return ret;
     208          31 :                     break;
     209             :                 case SSS_PAM_ITEM_RUSER:
     210          31 :                     ret = extract_string(&pd->ruser, size, body, blen, &c);
     211          31 :                     if (ret != EOK) return ret;
     212          31 :                     break;
     213             :                 case SSS_PAM_ITEM_RHOST:
     214          31 :                     ret = extract_string(&pd->rhost, size, body, blen, &c);
     215          31 :                     if (ret != EOK) return ret;
     216          31 :                     break;
     217             :                 case SSS_PAM_ITEM_REQUESTED_DOMAINS:
     218           1 :                     ret = extract_string(&requested_domains, size, body, blen,
     219             :                                          &c);
     220           1 :                     if (ret != EOK) return ret;
     221             : 
     222           1 :                     ret = split_on_separator(pd, requested_domains, ',', true,
     223             :                                              true, &pd->requested_domains,
     224             :                                              NULL);
     225           1 :                     if (ret != EOK) {
     226           0 :                         DEBUG(SSSDBG_CRIT_FAILURE,
     227             :                               "Failed to parse requested_domains list!\n");
     228           0 :                         return ret;
     229             :                     }
     230           1 :                     break;
     231             :                 case SSS_PAM_ITEM_CLI_PID:
     232          47 :                     ret = extract_uint32_t(&pd->cli_pid, size,
     233             :                                            body, blen, &c);
     234          47 :                     if (ret != EOK) return ret;
     235          47 :                     break;
     236             :                 case SSS_PAM_ITEM_AUTHTOK:
     237          24 :                     ret = extract_authtok_v2(pd->authtok,
     238             :                                              size, body, blen, &c);
     239          24 :                     if (ret != EOK) return ret;
     240          24 :                     break;
     241             :                 case SSS_PAM_ITEM_NEWAUTHTOK:
     242           1 :                     ret = extract_authtok_v2(pd->newauthtok,
     243             :                                              size, body, blen, &c);
     244           1 :                     if (ret != EOK) return ret;
     245           1 :                     break;
     246             :                 default:
     247           0 :                     DEBUG(SSSDBG_CRIT_FAILURE,
     248             :                           "Ignoring unknown data type [%d].\n", type);
     249           0 :                     c += size;
     250             :             }
     251             :         }
     252             : 
     253         303 :     } while(c < blen);
     254             : 
     255          47 :     return EOK;
     256             : 
     257             : }
     258             : 
     259          47 : static int pam_parse_in_data_v3(struct pam_data *pd,
     260             :                                 uint8_t *body, size_t blen)
     261             : {
     262             :     int ret;
     263             : 
     264          47 :     ret = pam_parse_in_data_v2(pd, body, blen);
     265          47 :     if (ret != EOK) {
     266           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "pam_parse_in_data_v2 failed.\n");
     267           0 :         return ret;
     268             :     }
     269             : 
     270          47 :     if (pd->cli_pid == 0) {
     271           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "Missing client PID.\n");
     272           0 :         return EINVAL;
     273             :     }
     274             : 
     275          47 :     return EOK;
     276             : }
     277             : 
     278         184 : static int extract_string(char **var, size_t size, uint8_t *body, size_t blen,
     279             :                           size_t *c)
     280             : {
     281             :     uint8_t *str;
     282             : 
     283         184 :     if (*c+size > blen || SIZE_T_OVERFLOW(*c, size)) return EINVAL;
     284             : 
     285         184 :     str = body+(*c);
     286             : 
     287         184 :     if (str[size-1]!='\0') return EINVAL;
     288             : 
     289             :     /* If the string isn't valid UTF-8, fail */
     290         184 :     if (!sss_utf8_check(str, size-1)) {
     291           0 :         return EINVAL;
     292             :     }
     293             : 
     294         184 :     *c += size;
     295             : 
     296         184 :     *var = (char *) str;
     297             : 
     298         184 :     return EOK;
     299             : }
     300             : 
     301          47 : static int extract_uint32_t(uint32_t *var, size_t size, uint8_t *body,
     302             :                             size_t blen, size_t *c)
     303             : {
     304             : 
     305          47 :     if (size != sizeof(uint32_t)
     306          47 :             || *c+size > blen
     307          47 :             || SIZE_T_OVERFLOW(*c, size)) {
     308           0 :         return EINVAL;
     309             :     }
     310             : 
     311          47 :     SAFEALIGN_COPY_UINT32_CHECK(var, &body[*c], blen, c);
     312             : 
     313          47 :     return EOK;
     314             : }
     315             : 
     316           0 : static int extract_authtok_v1(struct sss_auth_token *tok,
     317             :                               uint8_t *body, size_t blen, size_t *c)
     318             : {
     319             :     uint32_t auth_token_type;
     320             :     uint32_t auth_token_length;
     321             :     uint8_t *auth_token_data;
     322           0 :     int ret = EOK;
     323             : 
     324           0 :     SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
     325           0 :     SAFEALIGN_COPY_UINT32_CHECK(&auth_token_length, &body[*c], blen, c);
     326           0 :     auth_token_data = body+(*c);
     327             : 
     328           0 :     switch (auth_token_type) {
     329             :     case SSS_AUTHTOK_TYPE_EMPTY:
     330           0 :         sss_authtok_set_empty(tok);
     331           0 :         break;
     332             :     case SSS_AUTHTOK_TYPE_PASSWORD:
     333           0 :         ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
     334             :                                        auth_token_length);
     335           0 :         break;
     336             :     default:
     337           0 :         return EINVAL;
     338             :     }
     339             : 
     340           0 :     *c += auth_token_length;
     341             : 
     342           0 :     return ret;
     343             : }
     344             : 
     345          25 : static int extract_authtok_v2(struct sss_auth_token *tok,
     346             :                               size_t data_size, uint8_t *body, size_t blen,
     347             :                               size_t *c)
     348             : {
     349             :     uint32_t auth_token_type;
     350             :     uint32_t auth_token_length;
     351             :     uint8_t *auth_token_data;
     352          25 :     int ret = EOK;
     353             : 
     354          50 :     if (data_size < sizeof(uint32_t) || *c+data_size > blen ||
     355          25 :         SIZE_T_OVERFLOW(*c, data_size)) return EINVAL;
     356             : 
     357          25 :     SAFEALIGN_COPY_UINT32_CHECK(&auth_token_type, &body[*c], blen, c);
     358          25 :     auth_token_length = data_size - sizeof(uint32_t);
     359          25 :     auth_token_data = body+(*c);
     360             : 
     361          25 :     switch (auth_token_type) {
     362             :     case SSS_AUTHTOK_TYPE_EMPTY:
     363           0 :         sss_authtok_set_empty(tok);
     364           0 :         break;
     365             :     case SSS_AUTHTOK_TYPE_PASSWORD:
     366          20 :         if (auth_token_length == 0) {
     367           0 :             sss_authtok_set_empty(tok);
     368             :         } else {
     369          20 :             ret = sss_authtok_set_password(tok, (const char *)auth_token_data,
     370             :                                            auth_token_length);
     371             :         }
     372          20 :         break;
     373             :     case SSS_AUTHTOK_TYPE_2FA:
     374           4 :         ret = sss_authtok_set(tok, SSS_AUTHTOK_TYPE_2FA,
     375             :                               auth_token_data, auth_token_length);
     376           4 :         break;
     377             :     case SSS_AUTHTOK_TYPE_SC_PIN:
     378           1 :         ret = sss_authtok_set_sc_pin(tok, (const char *) auth_token_data,
     379             :                                      auth_token_length);
     380           1 :         break;
     381             :     case SSS_AUTHTOK_TYPE_SC_KEYPAD:
     382           0 :         sss_authtok_set_sc_keypad(tok);
     383           0 :         break;
     384             :     default:
     385           0 :         return EINVAL;
     386             :     }
     387             : 
     388          25 :     *c += auth_token_length;
     389             : 
     390          25 :     return ret;
     391             : }
     392             : 

Generated by: LCOV version 1.10