summaryrefslogtreecommitdiffstats
path: root/server/responder/pam/pamsrv_cmd.c
diff options
context:
space:
mode:
authorStephen Gallagher <sgallagh@redhat.com>2009-10-22 11:58:06 -0400
committerStephen Gallagher <sgallagh@redhat.com>2009-10-22 15:43:01 -0400
commitc2d7b2271eafd27b41736624e4e5da121073279d (patch)
tree517d165f3f229b4783d5568fd06a1b8a80d089ad /server/responder/pam/pamsrv_cmd.c
parentff75b1a0e342f694589c46d9d59c509ac69be980 (diff)
downloadsssd-c2d7b2271eafd27b41736624e4e5da121073279d.tar.gz
sssd-c2d7b2271eafd27b41736624e4e5da121073279d.tar.xz
sssd-c2d7b2271eafd27b41736624e4e5da121073279d.zip
Add support for offline auth cache timeout
This adds a new option (offline_credentials_expiration) to the [PAM] section of the sssd.conf If the user does not perform an online authentication within the timeout (in days), they will be denied auth once the timeout passes.
Diffstat (limited to 'server/responder/pam/pamsrv_cmd.c')
-rw-r--r--server/responder/pam/pamsrv_cmd.c171
1 files changed, 170 insertions, 1 deletions
diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c
index cfc973d99..f05709ff0 100644
--- a/server/responder/pam/pamsrv_cmd.c
+++ b/server/responder/pam/pamsrv_cmd.c
@@ -30,6 +30,20 @@
#include "responder/pam/pamsrv.h"
#include "db/sysdb.h"
+struct last_login_request {
+ struct tevent_context *ev;
+ struct sysdb_ctx *dbctx;
+ struct sysdb_attrs *mod_attrs;
+ struct sysdb_handle *handle;
+
+ struct ldb_result *res;
+ int error;
+
+ struct pam_auth_req *preq;
+};
+
+static void pam_reply(struct pam_auth_req *preq);
+
static int extract_authtok(uint32_t *type, uint32_t *size, uint8_t **tok, uint8_t *body, size_t blen, size_t *c) {
size_t data_size;
@@ -266,7 +280,146 @@ static int pam_parse_in_data(struct sss_names_ctx *snctx,
return EOK;
}
-static void pam_reply(struct pam_auth_req *preq);
+static void prepare_reply(struct last_login_request *llreq)
+{
+ struct pam_data *pd;
+
+ pd = llreq->preq->pd;
+
+ if (llreq->error != EOK && pd->pam_status == PAM_SUCCESS)
+ pd->pam_status = PAM_SYSTEM_ERR;
+
+ llreq->preq->callback(llreq->preq);
+}
+
+static void set_user_last_login_done(struct tevent_req *req)
+{
+ struct last_login_request *llreq =
+ tevent_req_callback_data(req,
+ struct last_login_request);
+ int ret;
+
+ ret = sysdb_transaction_commit_recv(req);
+ if(ret != EOK) {
+ DEBUG(2, ("set_last_login failed.\n"));
+ llreq->error = ret;
+ }
+
+ llreq->preq->pd->last_auth_saved = true;
+
+ prepare_reply(llreq);
+}
+
+static void set_user_last_login_req_done(struct tevent_req *subreq);
+static void set_user_last_login_req(struct tevent_req *req)
+{
+ struct last_login_request *llreq =
+ tevent_req_callback_data(req,
+ struct last_login_request);
+ struct tevent_req *subreq;
+ int ret;
+
+ ret = sysdb_transaction_recv(req, llreq, &llreq->handle);
+ if (ret != EOK) {
+ llreq->error = ret;
+ return prepare_reply(llreq);
+ }
+
+ subreq = sysdb_set_user_attr_send(llreq, llreq->ev, llreq->handle,
+ llreq->preq->domain,
+ llreq->preq->pd->user,
+ llreq->mod_attrs, SYSDB_MOD_REP);
+ if (!subreq) {
+ /* Cancel transaction */
+ talloc_zfree(llreq->handle);
+ llreq->error = EIO;
+ return prepare_reply(llreq);
+ }
+ tevent_req_set_callback(subreq, set_user_last_login_req_done, llreq);
+}
+
+static void set_user_last_login_req_done(struct tevent_req *subreq)
+{
+ struct last_login_request *llreq =
+ tevent_req_callback_data(subreq,
+ struct last_login_request);
+ struct tevent_req *req;
+ int ret;
+
+ ret = sysdb_set_user_attr_recv(subreq);
+ talloc_zfree(subreq);
+
+ DEBUG(4, ("set_user_attr_callback, status [%d][%s]\n", ret, strerror(ret)));
+
+ if (ret) {
+ llreq->error = ret;
+ goto fail;
+ }
+
+ req = sysdb_transaction_commit_send(llreq, llreq->ev, llreq->handle);
+ if (!req) {
+ llreq->error = ENOMEM;
+ goto fail;
+ }
+ tevent_req_set_callback(req, set_user_last_login_done, llreq);
+
+fail:
+ DEBUG(2, ("set_last_login failed.\n"));
+
+ /* cancel transaction */
+ talloc_zfree(llreq->handle);
+
+ prepare_reply(llreq);
+}
+
+static errno_t set_last_login(struct pam_auth_req *preq)
+{
+ struct last_login_request *llreq;
+ struct tevent_req *req;
+ errno_t ret;
+
+ llreq = talloc_zero(preq, struct last_login_request);
+ if (!llreq) {
+ ret = ENOMEM;
+ goto fail;
+ }
+ llreq->ev = preq->cctx->ev;
+ llreq->preq = preq;
+
+ llreq->mod_attrs = sysdb_new_attrs(llreq);
+ if (!llreq->mod_attrs) {
+ ret = ENOMEM;
+ goto fail;
+ }
+
+ ret = sysdb_attrs_add_long(llreq->mod_attrs, SYSDB_LAST_ONLINE_AUTH,
+ (long)time(NULL));
+ if (ret != EOK) {
+ goto fail;
+ }
+
+ ret = sysdb_get_ctx_from_list(preq->cctx->rctx->db_list,
+ preq->domain, &llreq->dbctx);
+ if (ret != EOK) {
+ DEBUG(0, ("Fatal: Sysdb CTX not found for this domain!\n"));
+ goto fail;
+ }
+
+ req = sysdb_transaction_send(llreq, llreq->ev, llreq->dbctx);
+ if (!req) {
+ DEBUG(1, ("Unable to acquire sysdb transaction lock\n"));
+ ret = EIO;
+ goto fail;
+ }
+
+ tevent_req_set_callback(req, set_user_last_login_req, llreq);
+ return EOK;
+
+fail:
+ talloc_free(llreq);
+ return ret;
+}
+
static void pam_reply_delay(struct tevent_context *ev, struct tevent_timer *te,
struct timeval tv, void *pvt)
{
@@ -352,6 +505,22 @@ static void pam_reply(struct pam_auth_req *preq)
return;
}
+ /* If this was a successful login, save the lastLogin time */
+ if (preq->domain->cache_credentials &&
+ pd->cmd == SSS_PAM_AUTHENTICATE &&
+ pd->pam_status == PAM_SUCCESS &&
+ !pd->offline_auth &&
+ !pd->last_auth_saved &&
+ NEED_CHECK_PROVIDER(preq->domain->provider)) {
+ ret = set_last_login(preq);
+ if (ret != EOK) {
+ err = ret;
+ goto done;
+ }
+
+ return;
+ }
+
ret = sss_packet_new(cctx->creq, 0, sss_packet_get_cmd(cctx->creq->in),
&cctx->creq->out);
if (ret != EOK) {