Blob Blame History Raw
From 7facd87e8ba34654fc9c46b4a42943e92acafffb Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Wed, 7 Feb 2018 11:03:21 -0500
Subject: [PATCH 16/16] daemon: don't return account expiration policy if not
 known

Right now we assume the user's shadow entry will always be available.
If it's not available, we return fields from it initialized to 0.

That leads to spurious password expired notifications in GNOME.

This commit throws a NOT_SUPPORTED error if the shadow file is off
limits.
---
 src/user.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/user.c b/src/user.c
index a83cfe4..cf7eb26 100644
--- a/src/user.c
+++ b/src/user.c
@@ -79,60 +79,61 @@ struct User {
         gchar *object_path;
 
         Daemon       *daemon;
 
         GKeyFile     *keyfile;
 
         uid_t         uid;
         gid_t         gid;
         gchar        *user_name;
         gchar        *real_name;
         AccountType   account_type;
         PasswordMode  password_mode;
         gchar        *password_hint;
         gchar        *home_dir;
         gchar        *shell;
         gchar        *email;
         gchar        *language;
         gchar        *x_session;
         gchar        *location;
         guint64       login_frequency;
         gint64        login_time;
         gint64        expiration_time;
         gint64        last_change_time;
         gint64        min_days_between_changes;
         gint64        max_days_between_changes;
         gint64        days_to_warn;
         gint64        days_after_expiration_until_lock;
         GVariant     *login_history;
         gchar        *icon_file;
         gchar        *default_icon_file;
+        gboolean      account_expiration_policy_known;
         gboolean      locked;
         gboolean      automatic_login;
         gboolean      system_account;
         gboolean      local_account;
         gboolean      cached;
 
         guint        *extension_ids;
         guint         n_extension_ids;
 };
 
 typedef struct UserClass
 {
         AccountsUserSkeletonClass parent_class;
 } UserClass;
 
 static void user_accounts_user_iface_init (AccountsUserIface *iface);
 
 G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init));
 
 static gint
 account_type_from_pwent (struct passwd *pwent)
 {
         struct group *grp;
         gint i;
 
         if (pwent->pw_uid == 0) {
                 g_debug ("user is root so account type is administrator");
                 return ACCOUNT_TYPE_ADMINISTRATOR;
         }
 
@@ -261,60 +262,61 @@ user_update_from_pwent (User          *user,
                 locked = TRUE;
         }
         else {
                 locked = FALSE;
         }
 
         if (user->locked != locked) {
                 user->locked = locked;
                 changed = TRUE;
                 g_object_notify (G_OBJECT (user), "locked");
         }
 
         if (passwd == NULL || passwd[0] != 0) {
                 mode = PASSWORD_MODE_REGULAR;
         }
         else {
                 mode = PASSWORD_MODE_NONE;
         }
 
         if (spent) {
                 if (spent->sp_lstchg == 0) {
                         mode = PASSWORD_MODE_SET_AT_LOGIN;
                 }
 
                 user->expiration_time = spent->sp_expire;
                 user->last_change_time  = spent->sp_lstchg;
                 user->min_days_between_changes = spent->sp_min;
                 user->max_days_between_changes = spent->sp_max;
                 user->days_to_warn  = spent->sp_warn;
                 user->days_after_expiration_until_lock = spent->sp_inact;
+                user->account_expiration_policy_known = TRUE;
         }
 
         if (user->password_mode != mode) {
                 user->password_mode = mode;
                 changed = TRUE;
                 g_object_notify (G_OBJECT (user), "password-mode");
         }
 
         user->system_account = !user_classify_is_human (user->uid, user->user_name, pwent->pw_shell, passwd);
 
         g_object_thaw_notify (G_OBJECT (user));
 
         if (changed)
                 accounts_user_emit_changed (ACCOUNTS_USER (user));
 }
 
 void
 user_update_from_keyfile (User     *user,
                           GKeyFile *keyfile)
 {
         gchar *s;
 
         g_object_freeze_notify (G_OBJECT (user));
 
         s = g_key_file_get_string (keyfile, "User", "Language", NULL);
         if (s != NULL) {
                 /* TODO: validate / normalize */
                 g_free (user->language);
                 user->language = s;
                 g_object_notify (G_OBJECT (user), "language");
@@ -1154,60 +1156,65 @@ user_set_x_session (AccountsUser          *auser,
 
         if (!get_caller_uid (context, &uid)) {
                 throw_error (context, ERROR_FAILED, "identifying caller failed");
                 return FALSE;
         }
 
         if (user->uid == (uid_t) uid)
                 action_id = "org.freedesktop.accounts.change-own-user-data";
         else
                 action_id = "org.freedesktop.accounts.user-administration";
 
         daemon_local_check_auth (user->daemon,
                                  user,
                                  action_id,
                                  TRUE,
                                  user_change_x_session_authorized_cb,
                                  context,
                                  g_strdup (x_session),
                                  (GDestroyNotify) g_free);
 
         return TRUE;
 }
 
 static void
 user_get_password_expiration_policy_authorized_cb (Daemon                *daemon,
                                                    User                  *user,
                                                    GDBusMethodInvocation *context,
                                                    gpointer               data)
 
 {
+        if (!user->account_expiration_policy_known) {
+                throw_error (context, ERROR_NOT_SUPPORTED, "account expiration policy unknown to accounts service");
+                return;
+        }
+
         accounts_user_complete_get_password_expiration_policy (ACCOUNTS_USER (user),
                                                                context,
                                                                user->expiration_time,
                                                                user->last_change_time,
                                                                user->min_days_between_changes,
                                                                user->max_days_between_changes,
                                                                user->days_to_warn,
                                                                user->days_after_expiration_until_lock);
 }
 
 static gboolean
 user_get_password_expiration_policy (AccountsUser          *auser,
                                      GDBusMethodInvocation *context)
 {
         User *user = (User*)auser;
         int uid;
         const gchar *action_id;
 
         if (!get_caller_uid (context, &uid)) {
                 throw_error (context, ERROR_FAILED, "identifying caller failed");
                 return FALSE;
         }
 
         if (user->uid == (uid_t) uid)
                 action_id = "org.freedesktop.accounts.change-own-user-data";
         else
                 action_id = "org.freedesktop.accounts.user-administration";
 
         daemon_local_check_auth (user->daemon,
                                  user,
-- 
2.14.3