Hi,

this patch should fix #239. All translatable strings are in the pam
client and now it should be quite easy to add new messages which should
be presented to the user.

It is quite easy to see this message for a console user, but currently a
GUI user needs a very fast eye to catch the message in the gdm or
screensaver window. Maybe we should ask the desktop people to send a
PAM_TEXT_INFO message e.g. with libnotify to the user's desktop.

bye,
Sumit
From 838ab215caf4674222ce5ef4497137fb9aee4650 Mon Sep 17 00:00:00 2001
From: Sumit Bose <sb...@redhat.com>
Date: Thu, 28 Jan 2010 17:19:03 +0100
Subject: [PATCH] Warn the user if authentication happens offline

---
 server/db/sysdb.h                 |    2 +-
 server/db/sysdb_ops.c             |   17 +++++--
 server/responder/pam/pamsrv_cmd.c |   20 +++++++++-
 server/tests/sysdb-tests.c        |    3 +-
 sss_client/pam_sss.c              |   82 +++++++++++++++++++++++++++++++++++++
 sss_client/sss_cli.h              |    5 ++
 6 files changed, 121 insertions(+), 8 deletions(-)

diff --git a/server/db/sysdb.h b/server/db/sysdb.h
index 9b77edf..a6d9e69 100644
--- a/server/db/sysdb.h
+++ b/server/db/sysdb.h
@@ -557,7 +557,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX 
*mem_ctx,
                                          const uint8_t *authtok,
                                          size_t authtok_size,
                                          struct confdb_ctx *cdb);
-int sysdb_cache_auth_recv(struct tevent_req *req);
+int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date);
 
 struct tevent_req *sysdb_store_custom_send(TALLOC_CTX *mem_ctx,
                                          struct tevent_context *ev,
diff --git a/server/db/sysdb_ops.c b/server/db/sysdb_ops.c
index 9a8c32e..33a3fb5 100644
--- a/server/db/sysdb_ops.c
+++ b/server/db/sysdb_ops.c
@@ -4648,6 +4648,7 @@ struct sysdb_cache_auth_state {
     struct sysdb_attrs *update_attrs;
     bool authentication_successful;
     struct sysdb_handle *handle;
+    time_t expire_date;
 };
 
 errno_t check_failed_login_attempts(TALLOC_CTX *mem_ctx, struct confdb_ctx 
*cdb,
@@ -4766,6 +4767,7 @@ struct tevent_req *sysdb_cache_auth_send(TALLOC_CTX 
*mem_ctx,
     state->update_attrs = NULL;
     state->authentication_successful = false;
     state->handle = NULL;
+    state->expire_date = 0;
 
     subreq = sysdb_search_user_by_name_send(state, ev, sysdb, NULL, domain,
                                             name, attrs);
@@ -4821,10 +4823,14 @@ static void sysdb_cache_auth_get_attrs_done(struct 
tevent_req *subreq)
     DEBUG(9, ("Offline credentials expiration is [%d] days.\n",
               cred_expiration));
 
-    if (cred_expiration && lastLogin + (cred_expiration * 86400) < time(NULL)) 
{
-        DEBUG(4, ("Cached user entry is too old.\n"));
-        ret = EACCES;
-        goto done;
+    if (cred_expiration) {
+        state->expire_date = lastLogin + (cred_expiration * 86400);
+        if (state->expire_date < time(NULL)) {
+            DEBUG(4, ("Cached user entry is too old.\n"));
+            state->expire_date = 0;
+            ret = EACCES;
+            goto done;
+        }
     }
 
     ret = check_failed_login_attempts(state, state->cdb, ldb_msg,
@@ -5024,10 +5030,11 @@ static void sysdb_cache_auth_done(struct tevent_req 
*subreq)
     return;
 }
 
-int sysdb_cache_auth_recv(struct tevent_req *req) {
+int sysdb_cache_auth_recv(struct tevent_req *req, time_t *expire_date) {
     struct sysdb_cache_auth_state *state = tevent_req_data(req,
                                                  struct 
sysdb_cache_auth_state);
     TEVENT_REQ_RETURN_ON_ERROR(req);
 
+    *expire_date = state->expire_date;
     return (state->authentication_successful ? EOK : EINVAL);
 }
diff --git a/server/responder/pam/pamsrv_cmd.c 
b/server/responder/pam/pamsrv_cmd.c
index f89e73c..a4573e6 100644
--- a/server/responder/pam/pamsrv_cmd.c
+++ b/server/responder/pam/pamsrv_cmd.c
@@ -626,13 +626,31 @@ static void pam_cache_auth_done(struct tevent_req *req)
     int ret;
     struct pam_auth_req *preq = tevent_req_callback_data(req,
                                                          struct pam_auth_req);
+    const uint32_t resp_type = SSS_PAM_USER_INFO_OFFLINE_AUTH;
+    const size_t resp_len = sizeof(uint32_t) + sizeof(long long);
+    uint8_t *resp;
+    time_t expire_date = 0;
+    long long dummy;
 
-    ret = sysdb_cache_auth_recv(req);
+    ret = sysdb_cache_auth_recv(req, &expire_date);
     talloc_zfree(req);
 
     switch (ret) {
         case EOK:
             preq->pd->pam_status = PAM_SUCCESS;
+            resp = talloc_size(preq->pd, resp_len);
+            if (resp == NULL) {
+                DEBUG(1, ("talloc_size failed, cannot prepare user info.\n"));
+            } else {
+                memcpy(resp, &resp_type, sizeof(uint32_t));
+                dummy = (long long) expire_date;
+                memcpy(resp+sizeof(uint32_t), &dummy, sizeof(long long));
+                ret = pam_add_response(preq->pd, SSS_PAM_USER_INFO, resp_len,
+                                       (const uint8_t *) resp);
+                if (ret != EOK) {
+                    DEBUG(1, ("pam_add_response failed.\n"));
+                }
+            }
             break;
         case ENOENT:
             preq->pd->pam_status = PAM_AUTHINFO_UNAVAIL;
diff --git a/server/tests/sysdb-tests.c b/server/tests/sysdb-tests.c
index 3cd5e7d..a456211 100644
--- a/server/tests/sysdb-tests.c
+++ b/server/tests/sysdb-tests.c
@@ -2285,6 +2285,7 @@ static void cached_authentication(const char *username, 
const char *password,
     struct test_data *data;
     struct tevent_req *req;
     int ret;
+    time_t expire_date;
 
     /* Setup */
     ret = setup_sysdb_tests(&test_ctx);
@@ -2306,7 +2307,7 @@ static void cached_authentication(const char *username, 
const char *password,
     ret = test_loop(data);
     fail_unless(ret == EOK, "test_loop failed.");
 
-    ret = sysdb_cache_auth_recv(req);
+    ret = sysdb_cache_auth_recv(req, &expire_date);
     fail_unless(ret == expected_result, "sysdb_cache_auth request does not "
                                         "return expected result [%d].",
                                         expected_result);
diff --git a/sss_client/pam_sss.c b/sss_client/pam_sss.c
index 2b11e26..df3dd12 100644
--- a/sss_client/pam_sss.c
+++ b/sss_client/pam_sss.c
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <stdint.h>
 #include <syslog.h>
+#include <time.h>
 
 #include <security/pam_modules.h>
 #include <security/pam_ext.h>
@@ -369,6 +370,79 @@ static int do_pam_conversation(pam_handle_t *pamh, const 
int msg_style,
     return PAM_SUCCESS;
 }
 
+static int user_info_offline_auth(pam_handle_t *pamh, size_t buflen,
+                                  uint8_t *buf)
+{
+    int ret;
+    long long expire_date;
+    struct tm tm;
+    char expire_str[128];
+    char user_msg[256];
+
+    expire_str[0] = '\0';
+
+    if (buflen != sizeof(uint32_t) + sizeof(long long)) {
+        D(("User info response data has the wrong size"));
+        return PAM_BUF_ERR;
+    }
+
+    memcpy(&expire_date, buf + sizeof(uint32_t), sizeof(long long));
+
+    if (expire_date > 0) {
+        if (localtime_r((time_t *) &expire_date, &tm) != NULL) {
+            ret = strftime(expire_str, sizeof(expire_str), "%c", &tm);
+            if (ret == 0) {
+                D(("strftime failed."));
+                expire_str[0] = '\0';
+            }
+        } else {
+            D(("localtime_r failed"));
+        }
+    }
+
+    ret = snprintf(user_msg, sizeof(user_msg), "%s%s%s.",
+               _("Offline authentication"),
+              expire_str[0] ? _(", your cached password will expire at: ") : 
"",
+              expire_str[0] ? expire_str : "");
+    if (ret < 0 || ret >= sizeof(user_msg)) {
+        D(("snprintf failed."));
+        return PAM_SYSTEM_ERR;
+    }
+
+    ret = do_pam_conversation(pamh, PAM_TEXT_INFO, user_msg, NULL, NULL);
+    if (ret != PAM_SUCCESS) {
+        D(("do_pam_conversation failed."));
+        return PAM_SYSTEM_ERR;
+    }
+
+    return PAM_SUCCESS;
+}
+
+static int eval_user_info_response(pam_handle_t *pamh, size_t buflen,
+                                   uint8_t *buf)
+{
+    int ret;
+    uint32_t type;
+
+    if (buflen < sizeof(uint32_t)) {
+        D(("User info response data is too short"));
+        return PAM_BUF_ERR;
+    }
+
+    memcpy(&type, buf, sizeof(uint32_t));
+
+    switch(type) {
+        case SSS_PAM_USER_INFO_OFFLINE_AUTH:
+            ret = user_info_offline_auth(pamh, buflen, buf);
+            break;
+        default:
+            D(("Unknown user info type [%d]", type));
+            ret = PAM_SYSTEM_ERR;
+    }
+
+    return ret;
+}
+
 static int eval_response(pam_handle_t *pamh, size_t buflen, uint8_t *buf)
 {
     int ret;
@@ -449,6 +523,14 @@ static int eval_response(pam_handle_t *pamh, size_t 
buflen, uint8_t *buf)
                     }
                 }
                 break;
+            case SSS_PAM_USER_INFO:
+                ret = eval_user_info_response(pamh, len, &buf[p]);
+                if (ret != PAM_SUCCESS) {
+                    D(("eval_user_info_response failed"));
+                }
+                break;
+            default:
+                D(("Unknown response type [%d]", type));
         }
         p += len;
 
diff --git a/sss_client/sss_cli.h b/sss_client/sss_cli.h
index 7d25711..c6bb5bd 100644
--- a/sss_client/sss_cli.h
+++ b/sss_client/sss_cli.h
@@ -174,6 +174,11 @@ enum response_type {
     SSS_PAM_ENV_ITEM,    /* only pam environment */
     SSS_ENV_ITEM,        /* only user environment */
     SSS_ALL_ENV_ITEM,    /* pam and user environment */
+    SSS_PAM_USER_INFO
+};
+
+enum user_info_type {
+    SSS_PAM_USER_INFO_OFFLINE_AUTH = 0x01
 };
 
 enum nss_status sss_nss_make_request(enum sss_cli_command cmd,
-- 
1.6.6

_______________________________________________
sssd-devel mailing list
sssd-devel@lists.fedorahosted.org
https://fedorahosted.org/mailman/listinfo/sssd-devel

Reply via email to