LCOV - code coverage report
Current view: top level - responder/pam - pam_LOCAL_domain.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 139 0.0 %
Date: 2016-06-29 Functions: 0 6 0.0 %

          Line data    Source code
       1             : /*
       2             :    SSSD
       3             : 
       4             :    PAM e credentials
       5             : 
       6             :    Copyright (C) Sumit Bose <sbose@redhat.com>    2009
       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             : #include <security/pam_modules.h>
      24             : 
      25             : #include "util/util.h"
      26             : #include "db/sysdb.h"
      27             : #include "util/crypto/sss_crypto.h"
      28             : #include "providers/data_provider.h"
      29             : #include "responder/pam/pamsrv.h"
      30             : 
      31             : 
      32             : #define NULL_CHECK_OR_JUMP(var, msg, ret, err, label) do { \
      33             :     if (var == NULL) { \
      34             :         DEBUG(SSSDBG_CRIT_FAILURE, msg); \
      35             :         ret = (err); \
      36             :         goto label; \
      37             :     } \
      38             : } while(0)
      39             : 
      40             : #define NEQ_CHECK_OR_JUMP(var, val, msg, ret, err, label) do { \
      41             :     if (var != (val)) { \
      42             :         DEBUG(SSSDBG_CRIT_FAILURE, msg); \
      43             :         ret = (err); \
      44             :         goto label; \
      45             :     } \
      46             : } while(0)
      47             : 
      48             : 
      49             : struct LOCAL_request {
      50             :     struct tevent_context *ev;
      51             :     struct sysdb_ctx *dbctx;
      52             :     struct sss_domain_info *domain;
      53             :     struct sysdb_attrs *mod_attrs;
      54             : 
      55             :     struct ldb_result *res;
      56             :     int error;
      57             : 
      58             :     struct pam_auth_req *preq;
      59             : };
      60             : 
      61           0 : static void prepare_reply(struct LOCAL_request *lreq)
      62             : {
      63             :     struct pam_data *pd;
      64             : 
      65           0 :     pd = lreq->preq->pd;
      66             : 
      67           0 :     if (lreq->error != EOK && pd->pam_status == PAM_SUCCESS)
      68           0 :         pd->pam_status = PAM_SYSTEM_ERR;
      69             : 
      70           0 :     lreq->preq->callback(lreq->preq);
      71           0 : }
      72             : 
      73           0 : static void do_successful_login(struct LOCAL_request *lreq)
      74             : {
      75             :     int ret;
      76             : 
      77           0 :     lreq->mod_attrs = sysdb_new_attrs(lreq);
      78           0 :     NULL_CHECK_OR_JUMP(lreq->mod_attrs, "sysdb_new_attrs failed.\n",
      79             :                        lreq->error, ENOMEM, done);
      80             : 
      81           0 :     ret = sysdb_attrs_add_long(lreq->mod_attrs,
      82             :                                SYSDB_LAST_LOGIN, (long)time(NULL));
      83           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_attrs_add_long failed.\n",
      84             :                       lreq->error, ret, done);
      85             : 
      86           0 :     ret = sysdb_attrs_add_long(lreq->mod_attrs, SYSDB_FAILED_LOGIN_ATTEMPTS, 0L);
      87           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_attrs_add_long failed.\n",
      88             :                       lreq->error, ret, done);
      89             : 
      90           0 :     ret = sysdb_set_user_attr(lreq->domain,
      91           0 :                               lreq->preq->pd->user,
      92             :                               lreq->mod_attrs, SYSDB_MOD_REP);
      93           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_set_user_attr failed.\n",
      94             :                       lreq->error, ret, done);
      95             : 
      96             : done:
      97           0 :     return;
      98             : }
      99             : 
     100           0 : static void do_failed_login(struct LOCAL_request *lreq)
     101             : {
     102             :     int ret;
     103             :     int failedLoginAttempts;
     104             :     struct pam_data *pd;
     105             : 
     106           0 :     pd = lreq->preq->pd;
     107           0 :     pd->pam_status = PAM_AUTH_ERR;
     108             : /* TODO: maybe add more inteligent delay calculation */
     109           0 :     pd->response_delay = 3;
     110             : 
     111           0 :     lreq->mod_attrs = sysdb_new_attrs(lreq);
     112           0 :     NULL_CHECK_OR_JUMP(lreq->mod_attrs, "sysdb_new_attrs failed.\n",
     113             :                        lreq->error, ENOMEM, done);
     114             : 
     115           0 :     ret = sysdb_attrs_add_long(lreq->mod_attrs,
     116             :                                SYSDB_LAST_FAILED_LOGIN, (long)time(NULL));
     117           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_attrs_add_long failed.\n",
     118             :                       lreq->error, ret, done);
     119             : 
     120           0 :     failedLoginAttempts = ldb_msg_find_attr_as_int(lreq->res->msgs[0],
     121             :                                                    SYSDB_FAILED_LOGIN_ATTEMPTS,
     122             :                                                    0);
     123           0 :     failedLoginAttempts++;
     124             : 
     125           0 :     ret = sysdb_attrs_add_long(lreq->mod_attrs,
     126             :                                SYSDB_FAILED_LOGIN_ATTEMPTS,
     127             :                                (long)failedLoginAttempts);
     128           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_attrs_add_long failed.\n",
     129             :                       lreq->error, ret, done);
     130             : 
     131           0 :     ret = sysdb_set_user_attr(lreq->domain,
     132           0 :                               lreq->preq->pd->user,
     133             :                               lreq->mod_attrs, SYSDB_MOD_REP);
     134           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_set_user_attr failed.\n",
     135             :                       lreq->error, ret, done);
     136             : 
     137             : done:
     138           0 :     return;
     139             : }
     140             : 
     141           0 : static void do_pam_acct_mgmt(struct LOCAL_request *lreq)
     142             : {
     143             :     const char *disabled;
     144             :     struct pam_data *pd;
     145             : 
     146           0 :     pd = lreq->preq->pd;
     147             : 
     148           0 :     disabled = ldb_msg_find_attr_as_string(lreq->res->msgs[0],
     149             :                                            SYSDB_DISABLED, NULL);
     150           0 :     if ((disabled != NULL) &&
     151           0 :         (strncasecmp(disabled, "false",5) != 0) &&
     152           0 :         (strncasecmp(disabled, "no",2) != 0) ) {
     153           0 :         pd->pam_status = PAM_PERM_DENIED;
     154             :     }
     155           0 : }
     156             : 
     157           0 : static void do_pam_chauthtok(struct LOCAL_request *lreq)
     158             : {
     159             :     int ret;
     160             :     const char *password;
     161             :     char *salt;
     162             :     char *new_hash;
     163             :     struct pam_data *pd;
     164             : 
     165           0 :     pd = lreq->preq->pd;
     166             : 
     167           0 :     ret = sss_authtok_get_password(pd->newauthtok, &password, NULL);
     168           0 :     if (ret) {
     169             :         /* TODO: should we allow null passwords via a config option ? */
     170           0 :         if (ret == ENOENT) {
     171           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Empty passwords are not allowed!\n");
     172             :         }
     173           0 :         lreq->error = EINVAL;
     174           0 :         goto done;
     175             :     }
     176             : 
     177           0 :     ret = s3crypt_gen_salt(lreq, &salt);
     178           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "Salt generation failed.\n",
     179             :                       lreq->error, ret, done);
     180           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "Using salt [%s]\n", salt);
     181             : 
     182           0 :     ret = s3crypt_sha512(lreq, password, salt, &new_hash);
     183           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "Hash generation failed.\n",
     184             :                       lreq->error, ret, done);
     185           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "New hash [%s]\n", new_hash);
     186             : 
     187           0 :     lreq->mod_attrs = sysdb_new_attrs(lreq);
     188           0 :     NULL_CHECK_OR_JUMP(lreq->mod_attrs, "sysdb_new_attrs failed.\n",
     189             :                        lreq->error, ENOMEM, done);
     190             : 
     191           0 :     ret = sysdb_attrs_add_string(lreq->mod_attrs, SYSDB_PWD, new_hash);
     192           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_attrs_add_string failed.\n",
     193             :                       lreq->error, ret, done);
     194             : 
     195           0 :     ret = sysdb_attrs_add_long(lreq->mod_attrs,
     196             :                                "lastPasswordChange", (long)time(NULL));
     197           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_attrs_add_long failed.\n",
     198             :                       lreq->error, ret, done);
     199             : 
     200           0 :     ret = sysdb_set_user_attr(lreq->domain,
     201           0 :                               lreq->preq->pd->user,
     202             :                               lreq->mod_attrs, SYSDB_MOD_REP);
     203           0 :     NEQ_CHECK_OR_JUMP(ret, EOK, "sysdb_set_user_attr failed.\n",
     204             :                       lreq->error, ret, done);
     205             : 
     206             : done:
     207           0 :     sss_authtok_set_empty(pd->newauthtok);
     208           0 : }
     209             : 
     210           0 : int LOCAL_pam_handler(struct pam_auth_req *preq)
     211             : {
     212             :     struct LOCAL_request *lreq;
     213             :     static const char *attrs[] = {SYSDB_NAME,
     214             :                                   SYSDB_PWD,
     215             :                                   SYSDB_DISABLED,
     216             :                                   SYSDB_LAST_LOGIN,
     217             :                                   "lastPasswordChange",
     218             :                                   "accountExpires",
     219             :                                   SYSDB_FAILED_LOGIN_ATTEMPTS,
     220             :                                   "passwordHint",
     221             :                                   "passwordHistory",
     222             :                                   SYSDB_LAST_FAILED_LOGIN,
     223             :                                   NULL};
     224             :     struct ldb_result *res;
     225           0 :     const char *username = NULL;
     226           0 :     const char *pwdhash = NULL;
     227           0 :     char *new_hash = NULL;
     228             :     const char *password;
     229           0 :     struct pam_data *pd = preq->pd;
     230             :     int ret;
     231             : 
     232           0 :     DEBUG(SSSDBG_CONF_SETTINGS, "LOCAL pam handler.\n");
     233             : 
     234           0 :     lreq = talloc_zero(preq, struct LOCAL_request);
     235           0 :     if (!lreq) {
     236           0 :         return ENOMEM;
     237             :     }
     238             : 
     239           0 :     lreq->dbctx = preq->domain->sysdb;
     240           0 :     if (lreq->dbctx == NULL) {
     241           0 :         DEBUG(SSSDBG_FATAL_FAILURE,
     242             :               "Fatal: Sysdb CTX not found for this domain!\n");
     243           0 :         talloc_free(lreq);
     244           0 :         return ENOENT;
     245             :     }
     246           0 :     lreq->domain = preq->domain;
     247           0 :     lreq->ev = preq->cctx->ev;
     248           0 :     lreq->preq = preq;
     249             : 
     250           0 :     pd->pam_status = PAM_SUCCESS;
     251             : 
     252           0 :     ret = sysdb_get_user_attr(lreq, preq->domain, preq->pd->user, attrs,
     253             :                               &res);
     254           0 :     if (ret != EOK) {
     255           0 :         DEBUG(SSSDBG_CRIT_FAILURE, "sysdb_get_user_attr failed.\n");
     256           0 :         talloc_free(lreq);
     257           0 :         return ret;
     258             :     }
     259             : 
     260           0 :     if (res->count < 1) {
     261           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
     262             :               "No user found with filter ["SYSDB_PWNAM_FILTER"]\n",
     263             :                   pd->user, pd->user, pd->user);
     264           0 :         pd->pam_status = PAM_USER_UNKNOWN;
     265           0 :         goto done;
     266           0 :     } else if (res->count > 1) {
     267           0 :         DEBUG(SSSDBG_CONF_SETTINGS,
     268             :               "More than one object found with filter ["SYSDB_PWNAM_FILTER"]\n",
     269             :                   pd->user, pd->user, pd->user);
     270           0 :         lreq->error = EFAULT;
     271           0 :         goto done;
     272             :     }
     273             : 
     274           0 :     username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
     275           0 :     if (strcmp(username, pd->user) != 0) {
     276           0 :         DEBUG(SSSDBG_CRIT_FAILURE,
     277             :               "Expected username [%s] get [%s].\n", pd->user, username);
     278           0 :         lreq->error = EINVAL;
     279           0 :         goto done;
     280             :     }
     281             : 
     282           0 :     lreq->res = res;
     283             : 
     284           0 :     switch (pd->cmd) {
     285             :         case SSS_PAM_AUTHENTICATE:
     286             :         case SSS_PAM_CHAUTHTOK:
     287             :         case SSS_PAM_CHAUTHTOK_PRELIM:
     288           0 :             if ((pd->cmd == SSS_PAM_CHAUTHTOK ||
     289           0 :                  pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) &&
     290           0 :                 lreq->preq->cctx->priv == 1) {
     291             : /* TODO: maybe this is a candiate for an explicit audit message. */
     292           0 :                 DEBUG(SSSDBG_CONF_SETTINGS,
     293             :                       "allowing root to reset a password.\n");
     294           0 :                 break;
     295             :             }
     296           0 :             ret = sss_authtok_get_password(pd->authtok, &password, NULL);
     297           0 :             NEQ_CHECK_OR_JUMP(ret, EOK, "Failed to get password.\n",
     298             :                               lreq->error, ret, done);
     299             : 
     300           0 :             pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL);
     301           0 :             NULL_CHECK_OR_JUMP(pwdhash, "No password stored.\n",
     302             :                                lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done);
     303           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     304             :                   "user: [%s], password hash: [%s]\n", username, pwdhash);
     305             : 
     306           0 :             ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash);
     307           0 :             NEQ_CHECK_OR_JUMP(ret, EOK, "nss_sha512_crypt failed.\n",
     308             :                               lreq->error, ret, done);
     309             : 
     310           0 :             DEBUG(SSSDBG_CONF_SETTINGS,
     311             :                   "user: [%s], new hash: [%s]\n", username, new_hash);
     312             : 
     313           0 :             if (strcmp(new_hash, pwdhash) != 0) {
     314           0 :                 DEBUG(SSSDBG_CRIT_FAILURE, "Passwords do not match.\n");
     315           0 :                 do_failed_login(lreq);
     316           0 :                 goto done;
     317             :             }
     318             : 
     319           0 :             break;
     320             :     }
     321             : 
     322           0 :     switch (pd->cmd) {
     323             :         case SSS_PAM_AUTHENTICATE:
     324           0 :             do_successful_login(lreq);
     325           0 :             break;
     326             :         case SSS_PAM_CHAUTHTOK:
     327           0 :             do_pam_chauthtok(lreq);
     328           0 :             break;
     329             :         case SSS_PAM_ACCT_MGMT:
     330           0 :             do_pam_acct_mgmt(lreq);
     331           0 :             break;
     332             :         case SSS_PAM_SETCRED:
     333           0 :             break;
     334             :         case SSS_PAM_OPEN_SESSION:
     335           0 :             break;
     336             :         case SSS_PAM_CLOSE_SESSION:
     337           0 :             break;
     338             :         case SSS_PAM_CHAUTHTOK_PRELIM:
     339           0 :             break;
     340             :         default:
     341           0 :             lreq->error = EINVAL;
     342           0 :             DEBUG(SSSDBG_CRIT_FAILURE, "Unknown PAM task [%d].\n", pd->cmd);
     343             :     }
     344             : 
     345             : done:
     346           0 :     sss_authtok_set_empty(pd->newauthtok);
     347           0 :     sss_authtok_set_empty(pd->authtok);
     348           0 :     prepare_reply(lreq);
     349           0 :     return EOK;
     350             : }
     351             : 

Generated by: LCOV version 1.10