Exemple #1
0
static void do_pam_chauthtok(struct LOCAL_request *lreq)
{
    int ret;
    const char *password;
    char *salt;
    char *new_hash;
    struct pam_data *pd;

    pd = lreq->preq->pd;

    ret = sss_authtok_get_password(pd->newauthtok, &password, NULL);
    if (ret) {
        /* TODO: should we allow null passwords via a config option ? */
        if (ret == ENOENT) {
            DEBUG(1, ("Empty passwords are not allowed!\n"));
        }
        lreq->error = EINVAL;
        goto done;
    }

    ret = s3crypt_gen_salt(lreq, &salt);
    NEQ_CHECK_OR_JUMP(ret, EOK, ("Salt generation failed.\n"),
                      lreq->error, ret, done);
    DEBUG(4, ("Using salt [%s]\n", salt));

    ret = s3crypt_sha512(lreq, password, salt, &new_hash);
    NEQ_CHECK_OR_JUMP(ret, EOK, ("Hash generation failed.\n"),
                      lreq->error, ret, done);
    DEBUG(4, ("New hash [%s]\n", new_hash));

    lreq->mod_attrs = sysdb_new_attrs(lreq);
    NULL_CHECK_OR_JUMP(lreq->mod_attrs, ("sysdb_new_attrs failed.\n"),
                       lreq->error, ENOMEM, done);

    ret = sysdb_attrs_add_string(lreq->mod_attrs, SYSDB_PWD, new_hash);
    NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_string failed.\n"),
                      lreq->error, ret, done);

    ret = sysdb_attrs_add_long(lreq->mod_attrs,
                               "lastPasswordChange", (long)time(NULL));
    NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_attrs_add_long failed.\n"),
                      lreq->error, ret, done);

    ret = sysdb_set_user_attr(lreq->dbctx, lreq->domain,
                              lreq->preq->pd->user,
                              lreq->mod_attrs, SYSDB_MOD_REP);
    NEQ_CHECK_OR_JUMP(ret, EOK, ("sysdb_set_user_attr failed.\n"),
                      lreq->error, ret, done);

done:
    sss_authtok_set_empty(pd->newauthtok);
}
Exemple #2
0
static void krb5_auth_cache_creds(struct krb5_ctx *krb5_ctx,
                                  struct sss_domain_info *domain,
                                  struct confdb_ctx *cdb,
                                  struct pam_data *pd, uid_t uid,
                                  int *pam_status, int *dp_err)
{
    const char *password = NULL;
    errno_t ret;

    if (sss_authtok_get_type(pd->authtok) != SSS_AUTHTOK_TYPE_PASSWORD) {
        DEBUG(SSSDBG_MINOR_FAILURE,
              "Delayed authentication is only available for password "
              "authentication (single factor).\n");
        return;
    }

    ret = sss_authtok_get_password(pd->authtok, &password, NULL);
    if (ret != EOK) {
        DEBUG(SSSDBG_FATAL_FAILURE,
              "Failed to get password [%d] %s\n", ret, strerror(ret));
        *pam_status = PAM_SYSTEM_ERR;
        *dp_err = DP_ERR_OK;
        return;
    }

    ret = sysdb_cache_auth(domain, pd->user,
                           password, cdb, true, NULL, NULL);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "Offline authentication failed\n");
        *pam_status = cached_login_pam_status(ret);
        *dp_err = DP_ERR_OK;
        return;
    }

    ret = add_user_to_delayed_online_authentication(krb5_ctx, pd, uid);
    if (ret != EOK) {
        /* This error is not fatal */
        DEBUG(SSSDBG_CRIT_FAILURE,
              "add_user_to_delayed_online_authentication failed.\n");
    }
    *pam_status = PAM_AUTHINFO_UNAVAIL;
    *dp_err = DP_ERR_OFFLINE;
}
Exemple #3
0
static void pam_reply(struct pam_auth_req *preq)
{
    struct cli_ctx *cctx;
    uint8_t *body;
    size_t blen;
    int ret;
    int32_t resp_c;
    int32_t resp_size;
    struct response_data *resp;
    int p;
    struct timeval tv;
    struct tevent_timer *te;
    struct pam_data *pd;
    struct pam_ctx *pctx;
    uint32_t user_info_type;
    time_t exp_date = -1;
    time_t delay_until = -1;

    pd = preq->pd;
    cctx = preq->cctx;
    pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);


    DEBUG(SSSDBG_FUNC_DATA,
          "pam_reply called with result [%d].\n", pd->pam_status);

    if (pd->pam_status == PAM_AUTHINFO_UNAVAIL) {
        switch(pd->cmd) {
        case SSS_PAM_AUTHENTICATE:
            if ((preq->domain != NULL) &&
                (preq->domain->cache_credentials == true) &&
                (pd->offline_auth == false)) {
                const char *password = NULL;

                /* do auth with offline credentials */
                pd->offline_auth = true;

                if (preq->domain->sysdb == NULL) {
                    DEBUG(SSSDBG_FATAL_FAILURE,
                          "Fatal: Sysdb CTX not found for domain"
                              " [%s]!\n", preq->domain->name);
                    goto done;
                }

                ret = sss_authtok_get_password(pd->authtok, &password, NULL);
                if (ret) {
                    DEBUG(SSSDBG_FATAL_FAILURE, "Failed to get password.\n");
                    goto done;
                }

                ret = sysdb_cache_auth(preq->domain,
                                       pd->user, password,
                                       pctx->rctx->cdb, false,
                                       &exp_date, &delay_until);

                pam_handle_cached_login(preq, ret, exp_date, delay_until);
                return;
            }
            break;
        case SSS_PAM_CHAUTHTOK_PRELIM:
        case SSS_PAM_CHAUTHTOK:
            DEBUG(SSSDBG_FUNC_DATA,
                  "Password change not possible while offline.\n");
            pd->pam_status = PAM_AUTHTOK_ERR;
            user_info_type = SSS_PAM_USER_INFO_OFFLINE_CHPASS;
            ret = pam_add_response(pd, SSS_PAM_USER_INFO, sizeof(uint32_t),
                                   (const uint8_t *) &user_info_type);
            if (ret != EOK) {
                DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
                goto done;
            }
            break;
/* TODO: we need the pam session cookie here to make sure that cached
 * authentication was successful */
        case SSS_PAM_SETCRED:
        case SSS_PAM_ACCT_MGMT:
        case SSS_PAM_OPEN_SESSION:
        case SSS_PAM_CLOSE_SESSION:
            DEBUG(SSSDBG_OP_FAILURE,
                  "Assuming offline authentication setting status for "
                      "pam call %d to PAM_SUCCESS.\n", pd->cmd);
            pd->pam_status = PAM_SUCCESS;
            break;
        default:
            DEBUG(SSSDBG_CRIT_FAILURE, "Unknown PAM call [%d].\n", pd->cmd);
            pd->pam_status = PAM_MODULE_UNKNOWN;
        }
    }

    if (pd->response_delay > 0) {
        ret = gettimeofday(&tv, NULL);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "gettimeofday failed [%d][%s].\n",
                      errno, strerror(errno));
            goto done;
        }
        tv.tv_sec += pd->response_delay;
        tv.tv_usec = 0;
        pd->response_delay = 0;

        te = tevent_add_timer(cctx->ev, cctx, tv, pam_reply_delay, preq);
        if (te == NULL) {
            DEBUG(SSSDBG_CRIT_FAILURE,
                  "Failed to add event pam_reply_delay.\n");
            goto done;
        }

        return;
    }

    /* If this was a successful login, save the lastLogin time */
    if (pd->cmd == SSS_PAM_AUTHENTICATE &&
        pd->pam_status == PAM_SUCCESS &&
        preq->domain->cache_credentials &&
        !pd->offline_auth &&
        !pd->last_auth_saved &&
        NEED_CHECK_PROVIDER(preq->domain->provider)) {
        ret = set_last_login(preq);
        if (ret != EOK) {
            goto done;
        }
        return;
    }

    ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
                         &cctx->creq->out);
    if (ret != EOK) {
        goto done;
    }

    ret = filter_responses(pctx->rctx->cdb, pd->resp_list);
    if (ret != EOK) {
        DEBUG(SSSDBG_CRIT_FAILURE, "filter_responses failed, not fatal.\n");
    }

    if (pd->domain != NULL) {
        ret = pam_add_response(pd, SSS_PAM_DOMAIN_NAME, strlen(pd->domain)+1,
                               (uint8_t *) pd->domain);
        if (ret != EOK) {
            DEBUG(SSSDBG_CRIT_FAILURE, "pam_add_response failed.\n");
            goto done;
        }
    }

    resp_c = 0;
    resp_size = 0;
    resp = pd->resp_list;
    while(resp != NULL) {
        if (!resp->do_not_send_to_client) {
            resp_c++;
            resp_size += resp->len;
        }
        resp = resp->next;
    }

    ret = sss_packet_grow(cctx->creq->out, sizeof(int32_t) +
                                           sizeof(int32_t) +
                                           resp_c * 2* sizeof(int32_t) +
                                           resp_size);
    if (ret != EOK) {
        goto done;
    }

    sss_packet_get_body(cctx->creq->out, &body, &blen);
    DEBUG(SSSDBG_FUNC_DATA, "blen: %zu\n", blen);
    p = 0;

    memcpy(&body[p], &pd->pam_status, sizeof(int32_t));
    p += sizeof(int32_t);

    memcpy(&body[p], &resp_c, sizeof(int32_t));
    p += sizeof(int32_t);

    resp = pd->resp_list;
    while(resp != NULL) {
        if (!resp->do_not_send_to_client) {
            memcpy(&body[p], &resp->type, sizeof(int32_t));
            p += sizeof(int32_t);
            memcpy(&body[p], &resp->len, sizeof(int32_t));
            p += sizeof(int32_t);
            memcpy(&body[p], resp->data, resp->len);
            p += resp->len;
        }

        resp = resp->next;
    }

done:
    sss_cmd_done(cctx, preq);
}
Exemple #4
0
static void krb5_auth_store_creds(struct sss_domain_info *domain,
                                  struct pam_data *pd)
{
    const char *password = NULL;
    const char *fa2;
    size_t password_len;
    size_t fa2_len = 0;
    int ret = EOK;

    switch(pd->cmd) {
        case SSS_CMD_RENEW:
            /* The authtok is set to the credential cache
             * during renewal. We don't want to save this
             * as the cached password.
             */
            break;
        case SSS_PAM_PREAUTH:
            /* There are no credentials available during pre-authentication,
             * nothing to do. */
            break;
        case SSS_PAM_AUTHENTICATE:
        case SSS_PAM_CHAUTHTOK_PRELIM:
            if (sss_authtok_get_type(pd->authtok) == SSS_AUTHTOK_TYPE_2FA) {
                ret = sss_authtok_get_2fa(pd->authtok, &password, &password_len,
                                          &fa2, &fa2_len);
                if (ret == EOK && password_len <
                                      domain->cache_credentials_min_ff_length) {
                    DEBUG(SSSDBG_FATAL_FAILURE,
                          "First factor is too short to be cache, "
                          "minimum length is [%u].\n",
                          domain->cache_credentials_min_ff_length);
                    ret = EINVAL;
                }
            } else if (sss_authtok_get_type(pd->authtok) ==
                                                    SSS_AUTHTOK_TYPE_PASSWORD) {
                ret = sss_authtok_get_password(pd->authtok, &password, NULL);
            } else {
                DEBUG(SSSDBG_MINOR_FAILURE, "Cannot cache authtok type [%d].\n",
                      sss_authtok_get_type(pd->authtok));
                ret = EINVAL;
            }
            break;
        case SSS_PAM_CHAUTHTOK:
            ret = sss_authtok_get_password(pd->newauthtok, &password, NULL);
            break;
        default:
            DEBUG(SSSDBG_FATAL_FAILURE,
                  "unsupported PAM command [%d].\n", pd->cmd);
    }

    if (ret != EOK) {
        DEBUG(SSSDBG_FATAL_FAILURE,
              "Failed to get password [%d] %s\n", ret, strerror(ret));
        /* password caching failures are not fatal errors */
        return;
    }

    if (password == NULL) {
        if (pd->cmd != SSS_CMD_RENEW && pd->cmd != SSS_PAM_PREAUTH) {
            DEBUG(SSSDBG_FATAL_FAILURE,
                  "password not available, offline auth may not work.\n");
            /* password caching failures are not fatal errors */
        }
        return;
    }

    ret = sysdb_cache_password_ex(domain, pd->user, password,
                                  sss_authtok_get_type(pd->authtok), fa2_len);
    if (ret) {
        DEBUG(SSSDBG_OP_FAILURE,
              "Failed to cache password, offline auth may not work."
                  " (%d)[%s]!?\n", ret, strerror(ret));
        /* password caching failures are not fatal errors */
    }
}
Exemple #5
0
int LOCAL_pam_handler(struct pam_auth_req *preq)
{
    struct LOCAL_request *lreq;
    static const char *attrs[] = {SYSDB_NAME,
                                  SYSDB_PWD,
                                  SYSDB_DISABLED,
                                  SYSDB_LAST_LOGIN,
                                  "lastPasswordChange",
                                  "accountExpires",
                                  SYSDB_FAILED_LOGIN_ATTEMPTS,
                                  "passwordHint",
                                  "passwordHistory",
                                  SYSDB_LAST_FAILED_LOGIN,
                                  NULL};
    struct ldb_result *res;
    const char *username = NULL;
    const char *pwdhash = NULL;
    char *new_hash = NULL;
    const char *password;
    struct pam_data *pd = preq->pd;
    int ret;

    DEBUG(4, ("LOCAL pam handler.\n"));

    lreq = talloc_zero(preq, struct LOCAL_request);
    if (!lreq) {
        return ENOMEM;
    }

    lreq->dbctx = preq->domain->sysdb;
    if (lreq->dbctx == NULL) {
        DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
        talloc_free(lreq);
        return ENOENT;
    }
    lreq->domain = preq->domain;
    lreq->ev = preq->cctx->ev;
    lreq->preq = preq;

    pd->pam_status = PAM_SUCCESS;

    ret = sysdb_get_user_attr(lreq, lreq->dbctx, preq->domain,
                              preq->pd->user, attrs, &res);
    if (ret != EOK) {
        DEBUG(1, ("sysdb_get_user_attr failed.\n"));
        talloc_free(lreq);
        return ret;
    }

    if (res->count < 1) {
        DEBUG(4, ("No user found with filter ["SYSDB_PWNAM_FILTER"]\n",
                  pd->user, pd->user));
        pd->pam_status = PAM_USER_UNKNOWN;
        goto done;
    } else if (res->count > 1) {
        DEBUG(4, ("More than one object found with filter ["SYSDB_PWNAM_FILTER"]\n",
                  pd->user, pd->user));
        lreq->error = EFAULT;
        goto done;
    }

    username = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_NAME, NULL);
    if (strcmp(username, pd->user) != 0) {
        DEBUG(1, ("Expected username [%s] get [%s].\n", pd->user, username));
        lreq->error = EINVAL;
        goto done;
    }

    lreq->res = res;

    switch (pd->cmd) {
        case SSS_PAM_AUTHENTICATE:
        case SSS_PAM_CHAUTHTOK:
        case SSS_PAM_CHAUTHTOK_PRELIM:
            if ((pd->cmd == SSS_PAM_CHAUTHTOK ||
                 pd->cmd == SSS_PAM_CHAUTHTOK_PRELIM) &&
                lreq->preq->cctx->priv == 1) {
/* TODO: maybe this is a candiate for an explicit audit message. */
                DEBUG(4, ("allowing root to reset a password.\n"));
                break;
            }
            ret = sss_authtok_get_password(pd->authtok, &password, NULL);
            NEQ_CHECK_OR_JUMP(ret, EOK, ("Failed to get password.\n"),
                               lreq->error, ret, done);

            pwdhash = ldb_msg_find_attr_as_string(res->msgs[0], SYSDB_PWD, NULL);
            NULL_CHECK_OR_JUMP(pwdhash, ("No password stored.\n"),
                               lreq->error, LDB_ERR_NO_SUCH_ATTRIBUTE, done);
            DEBUG(4, ("user: [%s], password hash: [%s]\n", username, pwdhash));

            ret = s3crypt_sha512(lreq, password, pwdhash, &new_hash);
            NEQ_CHECK_OR_JUMP(ret, EOK, ("nss_sha512_crypt failed.\n"),
                              lreq->error, ret, done);

            DEBUG(4, ("user: [%s], new hash: [%s]\n", username, new_hash));

            if (strcmp(new_hash, pwdhash) != 0) {
                DEBUG(1, ("Passwords do not match.\n"));
                do_failed_login(lreq);
                goto done;
            }

            break;
    }

    switch (pd->cmd) {
        case SSS_PAM_AUTHENTICATE:
            do_successful_login(lreq);
            break;
        case SSS_PAM_CHAUTHTOK:
            do_pam_chauthtok(lreq);
            break;
        case SSS_PAM_ACCT_MGMT:
            do_pam_acct_mgmt(lreq);
            break;
        case SSS_PAM_SETCRED:
            break;
        case SSS_PAM_OPEN_SESSION:
            break;
        case SSS_PAM_CLOSE_SESSION:
            break;
        case SSS_PAM_CHAUTHTOK_PRELIM:
            break;
        default:
            lreq->error = EINVAL;
            DEBUG(1, ("Unknown PAM task [%d].\n"));
    }

done:
    sss_authtok_set_empty(pd->newauthtok);
    sss_authtok_set_empty(pd->authtok);
    prepare_reply(lreq);
    return EOK;
}