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