summaryrefslogtreecommitdiff
path: root/server
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
parentff75b1a0e342f694589c46d9d59c509ac69be980 (diff)
downloadsssd-c2d7b2271eafd27b41736624e4e5da121073279d.tar.gz
sssd-c2d7b2271eafd27b41736624e4e5da121073279d.tar.bz2
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')
-rw-r--r--server/confdb/confdb.h1
-rw-r--r--server/config/etc/sssd.api.conf1
-rw-r--r--server/db/sysdb.h1
-rw-r--r--server/man/sssd.conf.5.xml21
-rw-r--r--server/providers/data_provider.h1
-rw-r--r--server/responder/pam/pamsrv.c3
-rw-r--r--server/responder/pam/pamsrv.h1
-rw-r--r--server/responder/pam/pamsrv_cache.c20
-rw-r--r--server/responder/pam/pamsrv_cmd.c171
9 files changed, 217 insertions, 3 deletions
diff --git a/server/confdb/confdb.h b/server/confdb/confdb.h
index 4d4e8c29..e535286f 100644
--- a/server/confdb/confdb.h
+++ b/server/confdb/confdb.h
@@ -64,6 +64,7 @@
/* PAM */
#define CONFDB_PAM_CONF_ENTRY "config/pam"
+#define CONFDB_PAM_CRED_TIMEOUT "offline_credentials_expiration"
/* Data Provider */
#define CONFDB_DP_CONF_ENTRY "config/dp"
diff --git a/server/config/etc/sssd.api.conf b/server/config/etc/sssd.api.conf
index 99e87b91..8ec6d9c2 100644
--- a/server/config/etc/sssd.api.conf
+++ b/server/config/etc/sssd.api.conf
@@ -31,6 +31,7 @@ filter_users_in_groups = bool, None, true
[pam]
# Authentication service
+offline_credentials_expiration = int, None
[provider]
#Available provider types
diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index 55852c55..dfb53aaf 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -61,6 +61,7 @@
#define SYSDB_KEYBOARD "keyboard"
#define SYSDB_SESSION "session"
#define SYSDB_LAST_LOGIN "lastLogin"
+#define SYSDB_LAST_ONLINE_AUTH "lastOnlineAuth"
#define SYSDB_USERPIC "userPicture"
#define SYSDB_LAST_UPDATE "lastUpdate"
diff --git a/server/man/sssd.conf.5.xml b/server/man/sssd.conf.5.xml
index 9baed088..f735b076 100644
--- a/server/man/sssd.conf.5.xml
+++ b/server/man/sssd.conf.5.xml
@@ -327,6 +327,27 @@
</varlistentry>
</variablelist>
</refsect2>
+ <refsect2 id='PAM'>
+ <title>PAM configuration options</title>
+ <para>
+ These options can be used to configure the
+ Pluggable Authentication Module (PAM) service.
+ </para>
+ <variablelist>
+ <varlistentry>
+ <term>offline_credentials_expiration (integer)</term>
+ <listitem>
+ <para>
+ If the authentication provider is offline, how
+ long should we allow cached logins (in days).
+ </para>
+ <para>
+ Default: 0 (No limit)
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect2>
</refsect1>
<refsect1 id='domain-sections'>
diff --git a/server/providers/data_provider.h b/server/providers/data_provider.h
index 57b318fd..1e97d04c 100644
--- a/server/providers/data_provider.h
+++ b/server/providers/data_provider.h
@@ -109,6 +109,7 @@ struct pam_data {
struct response_data *resp_list;
bool offline_auth;
+ bool last_auth_saved;
int priv;
uid_t pw_uid;
gid_t gr_gid;
diff --git a/server/responder/pam/pamsrv.c b/server/responder/pam/pamsrv.c
index 352c0469..626d2c55 100644
--- a/server/responder/pam/pamsrv.c
+++ b/server/responder/pam/pamsrv.c
@@ -116,6 +116,9 @@ static errno_t pam_get_config(struct pam_ctx *pctx,
struct confdb_ctx *cdb)
{
int ret = EOK;
+ ret = confdb_get_int(cdb, pctx, CONFDB_PAM_CONF_ENTRY,
+ CONFDB_PAM_CRED_TIMEOUT, 0,
+ &pctx->cred_expiration);
return ret;
}
diff --git a/server/responder/pam/pamsrv.h b/server/responder/pam/pamsrv.h
index 74115bcc..d87e166f 100644
--- a/server/responder/pam/pamsrv.h
+++ b/server/responder/pam/pamsrv.h
@@ -32,6 +32,7 @@ struct pam_auth_req;
typedef void (pam_dp_callback_t)(struct pam_auth_req *preq);
struct pam_ctx {
+ int cred_expiration;
struct resp_ctx *rctx;
};
diff --git a/server/responder/pam/pamsrv_cache.c b/server/responder/pam/pamsrv_cache.c
index 9c5c209f..1e1c5444 100644
--- a/server/responder/pam/pamsrv_cache.c
+++ b/server/responder/pam/pamsrv_cache.c
@@ -61,17 +61,21 @@ static void pam_cache_auth_callback(void *pvt, int ldb_status,
struct ldb_result *res)
{
struct pam_auth_req *preq;
+ struct pam_ctx *pctx;
struct pam_data *pd;
const char *userhash;
char *comphash;
char *password = NULL;
int i, ret;
+ uint64_t lastLogin = 0;
preq = talloc_get_type(pvt, struct pam_auth_req);
pd = preq->pd;
+ pctx = talloc_get_type(preq->cctx->rctx->pvt_ctx, struct pam_ctx);
+
if (ldb_status != LDB_SUCCESS) {
- DEBUG(4, ("User info retireval failed! (%d [%s])\n",
+ DEBUG(4, ("User info retrieval failed! (%d [%s])\n",
ldb_status, sysdb_error_to_errno(ldb_status)));
ret = PAM_SYSTEM_ERR;
@@ -86,12 +90,23 @@ static void pam_cache_auth_callback(void *pvt, int ldb_status,
}
if (res->count != 1) {
- DEBUG(4, ("Too manyt results for user [%s@%s].\n",
+ DEBUG(4, ("Too many results for user [%s@%s].\n",
pd->user, preq->domain->name));
ret = PAM_SYSTEM_ERR;
goto done;
}
+ /* Check offline_auth_cache_timeout */
+ lastLogin = ldb_msg_find_attr_as_uint64(res->msgs[0],
+ SYSDB_LAST_ONLINE_AUTH,
+ 0);
+ if (pctx->cred_expiration &&
+ lastLogin + (pctx->cred_expiration * 86400) < time(NULL)) {
+ DEBUG(4, ("Cached user entry is too old."));
+ ret = PAM_AUTHINFO_UNAVAIL;
+ goto done;
+ }
+
/* TODO: verify user account (failed logins, disabled, expired ...) */
ret = authtok2str(preq, pd->authtok, pd->authtok_size, &password);
@@ -139,6 +154,7 @@ int pam_cache_auth(struct pam_auth_req *preq)
SYSDB_CACHEDPWD,
SYSDB_DISABLED,
SYSDB_LAST_LOGIN,
+ SYSDB_LAST_ONLINE_AUTH,
"lastCachedPasswordChange",
"accountExpires",
"failedLoginAttempts",
diff --git a/server/responder/pam/pamsrv_cmd.c b/server/responder/pam/pamsrv_cmd.c
index cfc973d9..f05709ff 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) {