import accountsservice-0.6.55-2.el8
This commit is contained in:
parent
1ac0e10c54
commit
0adef15784
|
@ -0,0 +1,925 @@
|
|||
From 72427bd4fcae931298c670093f9cbd34ad58f59a Mon Sep 17 00:00:00 2001
|
||||
From: Ray Strode <rstrode@redhat.com>
|
||||
Date: Wed, 4 Aug 2021 19:54:59 -0400
|
||||
Subject: [PATCH] user: Introduce user templates for setting default session
|
||||
etc
|
||||
|
||||
At the moment there's no easy way to set a default session, or
|
||||
face icon or whatever for all users. If a user has never logged in
|
||||
before, we just generate their cache file from hardcoded defaults.
|
||||
|
||||
This commit introduces a template system to make it possible for
|
||||
admins to set up defaults on their own.
|
||||
|
||||
Admins can write either
|
||||
/etc/accountsservice/user-templates/administrator
|
||||
or
|
||||
/etc/accountsservice/user-templates/standard
|
||||
|
||||
files. These files follow the same format as
|
||||
|
||||
/var/lib/AccountsService/users/username
|
||||
|
||||
files, but will support substituting $HOME and $USER to the appropriate
|
||||
user specific values.
|
||||
|
||||
User templates also support an additional group [Template] that
|
||||
have an additional key EnvironmentFiles that specify a list
|
||||
of environment files to load (files with KEY=VALUE pairs in them).
|
||||
Any keys listed in those environment files will also get substituted.
|
||||
---
|
||||
data/administrator | 6 +
|
||||
data/meson.build | 10 ++
|
||||
data/standard | 6 +
|
||||
src/daemon.c | 8 +-
|
||||
src/meson.build | 1 +
|
||||
src/user.c | 284 ++++++++++++++++++++++++++++++++++++++++++++-
|
||||
src/user.h | 3 +-
|
||||
7 files changed, 305 insertions(+), 13 deletions(-)
|
||||
create mode 100644 data/administrator
|
||||
create mode 100644 data/standard
|
||||
|
||||
diff --git a/data/administrator b/data/administrator
|
||||
new file mode 100644
|
||||
index 0000000..ea043c9
|
||||
--- /dev/null
|
||||
+++ b/data/administrator
|
||||
@@ -0,0 +1,6 @@
|
||||
+[Template]
|
||||
+#EnvironmentFiles=/etc/os-release;
|
||||
+
|
||||
+[User]
|
||||
+Session=
|
||||
+Icon=${HOME}/.face
|
||||
diff --git a/data/meson.build b/data/meson.build
|
||||
index 2dc57c2..7d9bdcd 100644
|
||||
--- a/data/meson.build
|
||||
+++ b/data/meson.build
|
||||
@@ -22,30 +22,40 @@ service = act_namespace + '.service'
|
||||
configure_file(
|
||||
input: service + '.in',
|
||||
output: service,
|
||||
configuration: service_conf,
|
||||
install: true,
|
||||
install_dir: dbus_sys_dir,
|
||||
)
|
||||
|
||||
policy = act_namespace.to_lower() + '.policy'
|
||||
|
||||
i18n.merge_file(
|
||||
policy,
|
||||
input: policy + '.in',
|
||||
output: policy,
|
||||
po_dir: po_dir,
|
||||
install: true,
|
||||
install_dir: policy_dir,
|
||||
)
|
||||
|
||||
if install_systemd_unit_dir
|
||||
service = 'accounts-daemon.service'
|
||||
|
||||
configure_file(
|
||||
input: service + '.in',
|
||||
output: service,
|
||||
configuration: service_conf,
|
||||
install: true,
|
||||
install_dir: systemd_system_unit_dir,
|
||||
)
|
||||
endif
|
||||
+
|
||||
+install_data(
|
||||
+ 'administrator',
|
||||
+ install_dir: join_paths(act_datadir, 'accountsservice', 'user-templates'),
|
||||
+)
|
||||
+
|
||||
+install_data(
|
||||
+ 'standard',
|
||||
+ install_dir: join_paths(act_datadir, 'accountsservice', 'user-templates'),
|
||||
+)
|
||||
diff --git a/data/standard b/data/standard
|
||||
new file mode 100644
|
||||
index 0000000..ea043c9
|
||||
--- /dev/null
|
||||
+++ b/data/standard
|
||||
@@ -0,0 +1,6 @@
|
||||
+[Template]
|
||||
+#EnvironmentFiles=/etc/os-release;
|
||||
+
|
||||
+[User]
|
||||
+Session=
|
||||
+Icon=${HOME}/.face
|
||||
diff --git a/src/daemon.c b/src/daemon.c
|
||||
index 5ce0216..66ac7ba 100644
|
||||
--- a/src/daemon.c
|
||||
+++ b/src/daemon.c
|
||||
@@ -298,69 +298,63 @@ entry_generator_cachedir (Daemon *daemon,
|
||||
break;
|
||||
|
||||
/* Only load files in this directory */
|
||||
filename = g_build_filename (USERDIR, name, NULL);
|
||||
regular = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
|
||||
|
||||
if (regular) {
|
||||
errno = 0;
|
||||
pwent = getpwnam (name);
|
||||
if (pwent != NULL) {
|
||||
*shadow_entry = getspnam (pwent->pw_name);
|
||||
|
||||
return pwent;
|
||||
} else if (errno == 0) {
|
||||
g_debug ("user '%s' in cache dir but not present on system, removing", name);
|
||||
remove_cache_files (name);
|
||||
}
|
||||
else {
|
||||
g_warning ("failed to check if user '%s' in cache dir is present on system: %s",
|
||||
name, g_strerror (errno));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Last iteration */
|
||||
g_dir_close (dir);
|
||||
|
||||
/* Update all the users from the files in the cache dir */
|
||||
g_hash_table_iter_init (&iter, users);
|
||||
while (g_hash_table_iter_next (&iter, &key, &value)) {
|
||||
- const gchar *name = key;
|
||||
User *user = value;
|
||||
- g_autofree gchar *filename = NULL;
|
||||
- g_autoptr(GKeyFile) key_file = NULL;
|
||||
|
||||
- filename = g_build_filename (USERDIR, name, NULL);
|
||||
- key_file = g_key_file_new ();
|
||||
- if (g_key_file_load_from_file (key_file, filename, 0, NULL))
|
||||
- user_update_from_keyfile (user, key_file);
|
||||
+ user_update_from_cache (user);
|
||||
}
|
||||
|
||||
*state = NULL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct passwd *
|
||||
entry_generator_requested_users (Daemon *daemon,
|
||||
GHashTable *users,
|
||||
gpointer *state,
|
||||
struct spwd **shadow_entry)
|
||||
{
|
||||
DaemonPrivate *priv = daemon_get_instance_private (daemon);
|
||||
struct passwd *pwent;
|
||||
GList *node;
|
||||
|
||||
/* First iteration */
|
||||
if (*state == NULL) {
|
||||
*state = priv->explicitly_requested_users;
|
||||
}
|
||||
|
||||
/* Every iteration */
|
||||
|
||||
if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
|
||||
node = *state;
|
||||
while (node != NULL) {
|
||||
const char *name;
|
||||
|
||||
name = node->data;
|
||||
node = node->next;
|
||||
diff --git a/src/meson.build b/src/meson.build
|
||||
index 3970749..d3b0cb9 100644
|
||||
--- a/src/meson.build
|
||||
+++ b/src/meson.build
|
||||
@@ -1,59 +1,60 @@
|
||||
sources = []
|
||||
|
||||
gdbus_headers = []
|
||||
|
||||
ifaces = [
|
||||
['accounts-generated', 'org.freedesktop.', 'Accounts'],
|
||||
['accounts-user-generated', act_namespace + '.', 'User'],
|
||||
['realmd-generated', 'org.freedesktop.', 'realmd'],
|
||||
]
|
||||
|
||||
foreach iface: ifaces
|
||||
gdbus_sources = gnome.gdbus_codegen(
|
||||
iface[0],
|
||||
join_paths(data_dir, iface[1] + iface[2] + '.xml'),
|
||||
interface_prefix: iface[1],
|
||||
namespace: 'Accounts',
|
||||
)
|
||||
sources += gdbus_sources
|
||||
gdbus_headers += gdbus_sources[1]
|
||||
endforeach
|
||||
|
||||
deps = [
|
||||
gio_dep,
|
||||
gio_unix_dep,
|
||||
]
|
||||
|
||||
cflags = [
|
||||
'-DLOCALSTATEDIR="@0@"'.format(act_localstatedir),
|
||||
'-DDATADIR="@0@"'.format(act_datadir),
|
||||
+ '-DSYSCONFDIR="@0@"'.format(act_sysconfdir),
|
||||
'-DICONDIR="@0@"'.format(join_paths(act_localstatedir, 'lib', 'AccountsService', 'icons')),
|
||||
'-DUSERDIR="@0@"'.format(join_paths(act_localstatedir, 'lib', 'AccountsService', 'users')),
|
||||
]
|
||||
|
||||
libaccounts_generated = static_library(
|
||||
'accounts-generated',
|
||||
sources: sources,
|
||||
include_directories: top_inc,
|
||||
dependencies: deps,
|
||||
c_args: cflags,
|
||||
)
|
||||
|
||||
libaccounts_generated_dep = declare_dependency(
|
||||
sources: gdbus_headers,
|
||||
include_directories: include_directories('.'),
|
||||
dependencies: gio_dep,
|
||||
link_with: libaccounts_generated,
|
||||
)
|
||||
|
||||
sources = files(
|
||||
'daemon.c',
|
||||
'extensions.c',
|
||||
'main.c',
|
||||
'user.c',
|
||||
'user-classify.c',
|
||||
'util.c',
|
||||
'wtmp-helper.c',
|
||||
)
|
||||
|
||||
deps = [
|
||||
diff --git a/src/user.c b/src/user.c
|
||||
index 9f57af5..16c7721 100644
|
||||
--- a/src/user.c
|
||||
+++ b/src/user.c
|
||||
@@ -43,127 +43,384 @@
|
||||
#include <polkit/polkit.h>
|
||||
|
||||
#include "user-classify.h"
|
||||
#include "daemon.h"
|
||||
#include "user.h"
|
||||
#include "accounts-user-generated.h"
|
||||
#include "util.h"
|
||||
|
||||
struct User {
|
||||
AccountsUserSkeleton parent;
|
||||
|
||||
GDBusConnection *system_bus_connection;
|
||||
gchar *object_path;
|
||||
|
||||
Daemon *daemon;
|
||||
|
||||
GKeyFile *keyfile;
|
||||
|
||||
gid_t gid;
|
||||
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 cached;
|
||||
+ gboolean template_loaded;
|
||||
|
||||
guint *extension_ids;
|
||||
guint n_extension_ids;
|
||||
|
||||
guint changed_timeout_id;
|
||||
};
|
||||
|
||||
typedef struct UserClass
|
||||
{
|
||||
AccountsUserSkeletonClass parent_class;
|
||||
} UserClass;
|
||||
|
||||
static void user_accounts_user_iface_init (AccountsUserIface *iface);
|
||||
+static void user_update_from_keyfile (User *user, GKeyFile *keyfile);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
grp = getgrnam (ADMIN_GROUP);
|
||||
if (grp == NULL) {
|
||||
g_debug (ADMIN_GROUP " group not found");
|
||||
return ACCOUNT_TYPE_STANDARD;
|
||||
}
|
||||
|
||||
for (i = 0; grp->gr_mem[i] != NULL; i++) {
|
||||
if (g_strcmp0 (grp->gr_mem[i], pwent->pw_name) == 0) {
|
||||
return ACCOUNT_TYPE_ADMINISTRATOR;
|
||||
}
|
||||
}
|
||||
|
||||
return ACCOUNT_TYPE_STANDARD;
|
||||
}
|
||||
|
||||
static void
|
||||
user_reset_icon_file (User *user)
|
||||
{
|
||||
const char *icon_file;
|
||||
gboolean icon_is_default;
|
||||
const char *home_dir;
|
||||
|
||||
icon_file = accounts_user_get_icon_file (ACCOUNTS_USER (user));
|
||||
|
||||
if (icon_file == NULL || g_strcmp0 (icon_file, user->default_icon_file) == 0) {
|
||||
icon_is_default = TRUE;
|
||||
} else {
|
||||
icon_is_default = FALSE;
|
||||
}
|
||||
|
||||
g_free (user->default_icon_file);
|
||||
home_dir = accounts_user_get_home_directory (ACCOUNTS_USER (user));
|
||||
|
||||
user->default_icon_file = g_build_filename (home_dir, ".face", NULL);
|
||||
|
||||
if (icon_is_default) {
|
||||
accounts_user_set_icon_file (ACCOUNTS_USER (user), user->default_icon_file);
|
||||
}
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+user_has_cache_file (User *user)
|
||||
+{
|
||||
+ g_autofree char *filename = NULL;
|
||||
+
|
||||
+ filename = g_build_filename (USERDIR, user_get_user_name (user), NULL);
|
||||
+
|
||||
+ return g_file_test (filename, G_FILE_TEST_EXISTS);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+is_valid_shell_identifier_character (char c,
|
||||
+ gboolean first)
|
||||
+{
|
||||
+ return (!first && g_ascii_isdigit (c)) ||
|
||||
+ c == '_' ||
|
||||
+ g_ascii_isalpha (c);
|
||||
+}
|
||||
+
|
||||
+static char *
|
||||
+expand_template_variables (User *user,
|
||||
+ GHashTable *template_variables,
|
||||
+ const char *str)
|
||||
+{
|
||||
+ GString *s = g_string_new ("");
|
||||
+ const char *p, *start;
|
||||
+ char c;
|
||||
+
|
||||
+ p = str;
|
||||
+ while (*p) {
|
||||
+ c = *p;
|
||||
+ if (c == '\\') {
|
||||
+ p++;
|
||||
+ c = *p;
|
||||
+ if (c != '\0') {
|
||||
+ p++;
|
||||
+ switch (c) {
|
||||
+ case '\\':
|
||||
+ g_string_append_c (s, '\\');
|
||||
+ break;
|
||||
+ case '$':
|
||||
+ g_string_append_c (s, '$');
|
||||
+ break;
|
||||
+ default:
|
||||
+ g_string_append_c (s, '\\');
|
||||
+ g_string_append_c (s, c);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ } else if (c == '$') {
|
||||
+ gboolean brackets = FALSE;
|
||||
+ p++;
|
||||
+ if (*p == '{') {
|
||||
+ brackets = TRUE;
|
||||
+ p++;
|
||||
+ }
|
||||
+ start = p;
|
||||
+ while (*p != '\0' &&
|
||||
+ is_valid_shell_identifier_character (*p, p == start))
|
||||
+ p++;
|
||||
+ if (p == start || (brackets && *p != '}')) {
|
||||
+ g_string_append_c (s, '$');
|
||||
+ if (brackets)
|
||||
+ g_string_append_c (s, '{');
|
||||
+ g_string_append_len (s, start, p - start);
|
||||
+ } else {
|
||||
+ g_autofree char *variable = NULL;
|
||||
+ const char *value;
|
||||
+
|
||||
+ if (brackets && *p == '}')
|
||||
+ p++;
|
||||
+
|
||||
+ variable = g_strndup (start, p - start - 1);
|
||||
+
|
||||
+ value = g_hash_table_lookup (template_variables, variable);
|
||||
+ if (value) {
|
||||
+ g_string_append (s, value);
|
||||
+ }
|
||||
+ }
|
||||
+ } else {
|
||||
+ p++;
|
||||
+ g_string_append_c (s, c);
|
||||
+ }
|
||||
+ }
|
||||
+ return g_string_free (s, FALSE);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+load_template_environment_file (User *user,
|
||||
+ GHashTable *variables,
|
||||
+ const char *file)
|
||||
+{
|
||||
+ g_autofree char *contents = NULL;
|
||||
+ g_auto (GStrv) lines = NULL;
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ gboolean file_loaded;
|
||||
+ size_t i;
|
||||
+
|
||||
+ file_loaded = g_file_get_contents (file, &contents, NULL, &error);
|
||||
+
|
||||
+ if (!file_loaded) {
|
||||
+ g_debug ("Couldn't load template environment file %s: %s",
|
||||
+ file, error->message);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ lines = g_strsplit (contents, "\n", -1);
|
||||
+
|
||||
+ for (i = 0; lines[i] != NULL; i++) {
|
||||
+ char *p;
|
||||
+ char *variable_end;
|
||||
+ const char *variable;
|
||||
+ const char *value;
|
||||
+
|
||||
+ p = lines[i];
|
||||
+ while (g_ascii_isspace (*p))
|
||||
+ p++;
|
||||
+ if (*p == '#' || *p == '\0')
|
||||
+ continue;
|
||||
+ variable = p;
|
||||
+ while (is_valid_shell_identifier_character (*p, p == variable))
|
||||
+ p++;
|
||||
+ variable_end = p;
|
||||
+ while (g_ascii_isspace (*p))
|
||||
+ p++;
|
||||
+ if (variable_end == variable || *p != '=') {
|
||||
+ g_debug ("template environment file %s has invalid line '%s'\n", file, lines[i]);
|
||||
+ continue;
|
||||
+ }
|
||||
+ *variable_end = '\0';
|
||||
+ p++;
|
||||
+ while (g_ascii_isspace (*p))
|
||||
+ p++;
|
||||
+ value = p;
|
||||
+
|
||||
+ if (g_hash_table_lookup (variables, variable) == NULL) {
|
||||
+ g_hash_table_insert (variables,
|
||||
+ g_strdup (variable),
|
||||
+ g_strdup (value));
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+initialize_template_environment (User *user,
|
||||
+ GHashTable *variables,
|
||||
+ const char * const *files)
|
||||
+{
|
||||
+ size_t i;
|
||||
+
|
||||
+ g_hash_table_insert (variables, g_strdup ("HOME"), g_strdup (accounts_user_get_home_directory (ACCOUNTS_USER (user))));
|
||||
+ g_hash_table_insert (variables, g_strdup ("USER"), g_strdup (user_get_user_name (user)));
|
||||
+
|
||||
+ if (files == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ for (i = 0; files[i] != NULL; i++) {
|
||||
+ load_template_environment_file (user, variables, files[i]);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+user_update_from_template (User *user)
|
||||
+{
|
||||
+ g_autofree char *filename = NULL;
|
||||
+ g_autoptr (GKeyFile) key_file = NULL;
|
||||
+ g_autoptr (GError) error = NULL;
|
||||
+ g_autoptr (GHashTable) template_variables = NULL;
|
||||
+ g_auto (GStrv) template_environment_files = NULL;
|
||||
+ gboolean key_file_loaded = FALSE;
|
||||
+ const char * const *system_dirs[] = {
|
||||
+ (const char *[]) { "/run", SYSCONFDIR, NULL },
|
||||
+ g_get_system_data_dirs (),
|
||||
+ NULL
|
||||
+ };
|
||||
+ g_autoptr (GPtrArray) dirs = NULL;
|
||||
+ AccountType account_type;
|
||||
+ const char *account_type_string;
|
||||
+ size_t i, j;
|
||||
+ g_autofree char *contents = NULL;
|
||||
+ g_autofree char *expanded = NULL;
|
||||
+ g_auto (GStrv) lines = NULL;
|
||||
+
|
||||
+ if (user->template_loaded)
|
||||
+ return;
|
||||
+
|
||||
+ filename = g_build_filename (USERDIR,
|
||||
+ accounts_user_get_user_name (ACCOUNTS_USER (user)),
|
||||
+ NULL);
|
||||
+
|
||||
+ account_type = accounts_user_get_account_type (ACCOUNTS_USER (user));
|
||||
+ if (account_type == ACCOUNT_TYPE_ADMINISTRATOR)
|
||||
+ account_type_string = "administrator";
|
||||
+ else
|
||||
+ account_type_string = "standard";
|
||||
+
|
||||
+ dirs = g_ptr_array_new ();
|
||||
+ for (i = 0; system_dirs[i] != NULL; i++) {
|
||||
+ for (j = 0; system_dirs[i][j] != NULL; j++) {
|
||||
+ char *dir;
|
||||
+
|
||||
+ dir = g_build_filename (system_dirs[i][j],
|
||||
+ "accountsservice",
|
||||
+ "user-templates",
|
||||
+ NULL);
|
||||
+ g_ptr_array_add (dirs, dir);
|
||||
+ }
|
||||
+ }
|
||||
+ g_ptr_array_add (dirs, NULL);
|
||||
+
|
||||
+ key_file = g_key_file_new ();
|
||||
+ key_file_loaded = g_key_file_load_from_dirs (key_file,
|
||||
+ account_type_string,
|
||||
+ (const char **) dirs->pdata,
|
||||
+ NULL,
|
||||
+ G_KEY_FILE_KEEP_COMMENTS,
|
||||
+ &error);
|
||||
+
|
||||
+ if (!key_file_loaded) {
|
||||
+ g_debug ("failed to load user template: %s", error->message);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ template_variables = g_hash_table_new_full (g_str_hash,
|
||||
+ g_str_equal,
|
||||
+ g_free,
|
||||
+ g_free);
|
||||
+
|
||||
+ template_environment_files = g_key_file_get_string_list (key_file,
|
||||
+ "Template",
|
||||
+ "EnvironmentFiles",
|
||||
+ NULL,
|
||||
+ NULL);
|
||||
+
|
||||
+ initialize_template_environment (user, template_variables, (const char * const *) template_environment_files);
|
||||
+
|
||||
+ g_key_file_remove_group (key_file, "Template", NULL);
|
||||
+ contents = g_key_file_to_data (key_file, NULL, NULL);
|
||||
+ lines = g_strsplit (contents, "\n", -1);
|
||||
+
|
||||
+ expanded = expand_template_variables (user, template_variables, contents);
|
||||
+
|
||||
+ key_file_loaded = g_key_file_load_from_data (key_file,
|
||||
+ expanded,
|
||||
+ strlen (expanded),
|
||||
+ G_KEY_FILE_KEEP_COMMENTS,
|
||||
+ &error);
|
||||
+
|
||||
+ if (key_file_loaded)
|
||||
+ user_update_from_keyfile (user, key_file);
|
||||
+
|
||||
+ user->template_loaded = key_file_loaded;
|
||||
+}
|
||||
+
|
||||
void
|
||||
user_update_from_pwent (User *user,
|
||||
struct passwd *pwent,
|
||||
struct spwd *spent)
|
||||
{
|
||||
g_autofree gchar *real_name = NULL;
|
||||
gboolean is_system_account;
|
||||
const gchar *passwd;
|
||||
gboolean locked;
|
||||
PasswordMode mode;
|
||||
AccountType account_type;
|
||||
|
||||
g_object_freeze_notify (G_OBJECT (user));
|
||||
|
||||
if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
|
||||
gchar *first_comma = NULL;
|
||||
gchar *valid_utf8_name = NULL;
|
||||
|
||||
if (g_utf8_validate (pwent->pw_gecos, -1, NULL)) {
|
||||
valid_utf8_name = pwent->pw_gecos;
|
||||
first_comma = g_utf8_strchr (valid_utf8_name, -1, ',');
|
||||
}
|
||||
else {
|
||||
g_warning ("User %s has invalid UTF-8 in GECOS field. "
|
||||
"It would be a good thing to check /etc/passwd.",
|
||||
pwent->pw_name ? pwent->pw_name : "");
|
||||
}
|
||||
|
||||
if (first_comma) {
|
||||
real_name = g_strndup (valid_utf8_name,
|
||||
@@ -212,134 +469,150 @@ user_update_from_pwent (User *user,
|
||||
accounts_user_set_locked (ACCOUNTS_USER (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;
|
||||
}
|
||||
|
||||
accounts_user_set_password_mode (ACCOUNTS_USER (user), mode);
|
||||
is_system_account = !user_classify_is_human (accounts_user_get_uid (ACCOUNTS_USER (user)),
|
||||
accounts_user_get_user_name (ACCOUNTS_USER (user)),
|
||||
accounts_user_get_shell (ACCOUNTS_USER (user)),
|
||||
passwd);
|
||||
accounts_user_set_system_account (ACCOUNTS_USER (user), is_system_account);
|
||||
|
||||
+ if (!user_has_cache_file (user))
|
||||
+ user_update_from_template (user);
|
||||
g_object_thaw_notify (G_OBJECT (user));
|
||||
}
|
||||
|
||||
-void
|
||||
+static 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) {
|
||||
accounts_user_set_language (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "XSession", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_xsession (ACCOUNTS_USER (user), s);
|
||||
|
||||
/* for backward compat */
|
||||
accounts_user_set_session (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "Session", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_session (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "SessionType", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_session_type (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "Email", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_email (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "Location", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_location (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "PasswordHint", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_password_hint (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
s = g_key_file_get_string (keyfile, "User", "Icon", NULL);
|
||||
if (s != NULL) {
|
||||
accounts_user_set_icon_file (ACCOUNTS_USER (user), s);
|
||||
g_clear_pointer (&s, g_free);
|
||||
}
|
||||
|
||||
if (g_key_file_has_key (keyfile, "User", "SystemAccount", NULL)) {
|
||||
gboolean system_account;
|
||||
|
||||
system_account = g_key_file_get_boolean (keyfile, "User", "SystemAccount", NULL);
|
||||
accounts_user_set_system_account (ACCOUNTS_USER (user), system_account);
|
||||
}
|
||||
|
||||
g_clear_pointer (&user->keyfile, g_key_file_unref);
|
||||
user->keyfile = g_key_file_ref (keyfile);
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+user_update_from_cache (User *user)
|
||||
+{
|
||||
+ g_autofree gchar *filename = NULL;
|
||||
+ g_autoptr(GKeyFile) key_file = NULL;
|
||||
+
|
||||
+ filename = g_build_filename (USERDIR, accounts_user_get_user_name (ACCOUNTS_USER (user)), NULL);
|
||||
+
|
||||
+ key_file = g_key_file_new ();
|
||||
+
|
||||
+ if (!g_key_file_load_from_file (key_file, filename, 0, NULL))
|
||||
+ return;
|
||||
+
|
||||
+ g_object_freeze_notify (G_OBJECT (user));
|
||||
+ user_update_from_keyfile (user, key_file);
|
||||
user_set_cached (user, TRUE);
|
||||
user_set_saved (user, TRUE);
|
||||
-
|
||||
g_object_thaw_notify (G_OBJECT (user));
|
||||
}
|
||||
|
||||
void
|
||||
user_update_local_account_property (User *user,
|
||||
gboolean local)
|
||||
{
|
||||
accounts_user_set_local_account (ACCOUNTS_USER (user), local);
|
||||
}
|
||||
|
||||
void
|
||||
user_update_system_account_property (User *user,
|
||||
gboolean system)
|
||||
{
|
||||
accounts_user_set_system_account (ACCOUNTS_USER (user), system);
|
||||
}
|
||||
|
||||
static void
|
||||
user_save_to_keyfile (User *user,
|
||||
GKeyFile *keyfile)
|
||||
{
|
||||
g_key_file_remove_group (keyfile, "User", NULL);
|
||||
|
||||
if (accounts_user_get_email (ACCOUNTS_USER (user)))
|
||||
g_key_file_set_string (keyfile, "User", "Email", accounts_user_get_email (ACCOUNTS_USER (user)));
|
||||
|
||||
if (accounts_user_get_language (ACCOUNTS_USER (user)))
|
||||
g_key_file_set_string (keyfile, "User", "Language", accounts_user_get_language (ACCOUNTS_USER (user)));
|
||||
|
||||
if (accounts_user_get_session (ACCOUNTS_USER (user)))
|
||||
@@ -509,60 +782,63 @@ user_extension_set_property (User *user,
|
||||
if (!prev || !g_str_equal (printed, prev)) {
|
||||
g_key_file_set_value (user->keyfile, interface->name, property->name, printed);
|
||||
|
||||
/* Emit a change signal. Use invalidation
|
||||
* because the data may not be world-readable.
|
||||
*/
|
||||
g_dbus_connection_emit_signal (g_dbus_method_invocation_get_connection (invocation),
|
||||
NULL, /* destination_bus_name */
|
||||
g_dbus_method_invocation_get_object_path (invocation),
|
||||
"org.freedesktop.DBus.Properties", "PropertiesChanged",
|
||||
g_variant_new_parsed ("( %s, %a{sv}, [ %s ] )",
|
||||
interface->name, NULL, property->name),
|
||||
NULL);
|
||||
|
||||
accounts_user_emit_changed (ACCOUNTS_USER (user));
|
||||
save_extra_data (user);
|
||||
}
|
||||
|
||||
g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
|
||||
}
|
||||
|
||||
static void
|
||||
user_extension_authentication_done (Daemon *daemon,
|
||||
User *user,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusInterfaceInfo *interface = user_data;
|
||||
const gchar *method_name;
|
||||
|
||||
+ if (!user_has_cache_file (user))
|
||||
+ user_update_from_template (user);
|
||||
+
|
||||
method_name = g_dbus_method_invocation_get_method_name (invocation);
|
||||
|
||||
if (g_str_equal (method_name, "Get"))
|
||||
user_extension_get_property (user, daemon, interface, invocation);
|
||||
else if (g_str_equal (method_name, "GetAll"))
|
||||
user_extension_get_all_properties (user, daemon, interface, invocation);
|
||||
else if (g_str_equal (method_name, "Set"))
|
||||
user_extension_set_property (user, daemon, interface, invocation);
|
||||
else
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
user_extension_method_call (GDBusConnection *connection,
|
||||
const gchar *sender,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *method_name,
|
||||
GVariant *parameters,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gpointer user_data)
|
||||
{
|
||||
User *user = user_data;
|
||||
GDBusInterfaceInfo *iface_info;
|
||||
const gchar *annotation_name;
|
||||
const gchar *action_id;
|
||||
gint uid;
|
||||
gint i;
|
||||
|
||||
/* We don't allow method calls on extension interfaces, so we
|
||||
diff --git a/src/user.h b/src/user.h
|
||||
index b3b3380..eb81918 100644
|
||||
--- a/src/user.h
|
||||
+++ b/src/user.h
|
||||
@@ -30,58 +30,57 @@
|
||||
#include "types.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define TYPE_USER (user_get_type ())
|
||||
#define USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TYPE_USER, User))
|
||||
#define IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TYPE_USER))
|
||||
|
||||
typedef enum {
|
||||
ACCOUNT_TYPE_STANDARD,
|
||||
ACCOUNT_TYPE_ADMINISTRATOR,
|
||||
#define ACCOUNT_TYPE_LAST ACCOUNT_TYPE_ADMINISTRATOR
|
||||
} AccountType;
|
||||
|
||||
typedef enum {
|
||||
PASSWORD_MODE_REGULAR,
|
||||
PASSWORD_MODE_SET_AT_LOGIN,
|
||||
PASSWORD_MODE_NONE,
|
||||
#define PASSWORD_MODE_LAST PASSWORD_MODE_NONE
|
||||
} PasswordMode;
|
||||
|
||||
/* local methods */
|
||||
|
||||
GType user_get_type (void) G_GNUC_CONST;
|
||||
User * user_new (Daemon *daemon,
|
||||
uid_t uid);
|
||||
|
||||
void user_update_from_pwent (User *user,
|
||||
struct passwd *pwent,
|
||||
struct spwd *spent);
|
||||
-void user_update_from_keyfile (User *user,
|
||||
- GKeyFile *keyfile);
|
||||
+void user_update_from_cache (User *user);
|
||||
void user_update_local_account_property (User *user,
|
||||
gboolean local);
|
||||
void user_update_system_account_property (User *user,
|
||||
gboolean system);
|
||||
gboolean user_get_cached (User *user);
|
||||
void user_set_cached (User *user,
|
||||
gboolean cached);
|
||||
void user_set_saved (User *user,
|
||||
gboolean saved);
|
||||
|
||||
void user_register (User *user);
|
||||
void user_unregister (User *user);
|
||||
void user_changed (User *user);
|
||||
|
||||
void user_save (User *user);
|
||||
|
||||
const gchar * user_get_user_name (User *user);
|
||||
gboolean user_get_system_account (User *user);
|
||||
gboolean user_get_local_account (User *user);
|
||||
const gchar * user_get_object_path (User *user);
|
||||
uid_t user_get_uid (User *user);
|
||||
const gchar * user_get_shell (User *user);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif
|
||||
--
|
||||
2.27.0
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
# This file contains defaults for new users. To edit, first
|
||||
# copy it to /etc/accountsservice/user-templates and make changes
|
||||
# there
|
||||
[Template]
|
||||
EnvironmentFiles=/etc/os-release;
|
||||
|
||||
[com.redhat.AccountsServiceUser.System]
|
||||
id='${ID}'
|
||||
version-id='${VERSION_ID}'
|
||||
|
||||
[User]
|
||||
Session=gnome
|
||||
Icon=${HOME}/.face
|
|
@ -2,13 +2,14 @@
|
|||
|
||||
Name: accountsservice
|
||||
Version: 0.6.55
|
||||
Release: 1%{?dist}
|
||||
Release: 2%{?dist}
|
||||
Summary: D-Bus interfaces for querying and manipulating user account information
|
||||
License: GPLv3+
|
||||
URL: https://www.freedesktop.org/wiki/Software/AccountsService/
|
||||
|
||||
#VCS: git:git://git.freedesktop.org/accountsservice
|
||||
Source0: http://www.freedesktop.org/software/accountsservice/accountsservice-%{version}.tar.xz
|
||||
Source1: user-template
|
||||
|
||||
BuildRequires: gettext-devel
|
||||
BuildRequires: pkgconfig(dbus-1)
|
||||
|
@ -31,6 +32,8 @@ Patch20001: 0001-daemon-if-no-local-users-check-if-machine-is-enrolle.patch
|
|||
|
||||
Patch30001: 0001-lib-save-os-when-creating-user.patch
|
||||
|
||||
Patch40001: 0001-user-Introduce-user-templates-for-setting-default-se.patch
|
||||
|
||||
%description
|
||||
The accountsservice project provides a set of D-Bus interfaces for
|
||||
querying and manipulating user account information and an implementation
|
||||
|
@ -65,6 +68,11 @@ files needed to build applications that use accountsservice-libs.
|
|||
%install
|
||||
%meson_install
|
||||
|
||||
mkdir -p $RPM_BUILD_ROOT%{_datadir}/accountsservice/user-templates $RPM_BUILD_ROOT%{_sysconfdir}/accountsservice/user-templates
|
||||
cp $RPM_SOURCE_DIR/user-template $RPM_BUILD_ROOT%{_datadir}/accountsservice/user-templates/standard
|
||||
cp $RPM_SOURCE_DIR/user-template $RPM_BUILD_ROOT%{_datadir}/accountsservice/user-templates/administrator
|
||||
|
||||
|
||||
%find_lang accounts-service
|
||||
|
||||
%ldconfig_scriptlets libs
|
||||
|
@ -81,6 +89,8 @@ files needed to build applications that use accountsservice-libs.
|
|||
%files -f accounts-service.lang
|
||||
%license COPYING
|
||||
%doc README.md AUTHORS
|
||||
%dir %{_sysconfdir}/accountsservice/user-templates
|
||||
%dir %{_sysconfdir}/accountsservice
|
||||
%{_sysconfdir}/dbus-1/system.d/org.freedesktop.Accounts.conf
|
||||
%{_libexecdir}/accounts-daemon
|
||||
%{_datadir}/dbus-1/interfaces/org.freedesktop.Accounts.xml
|
||||
|
@ -88,6 +98,8 @@ files needed to build applications that use accountsservice-libs.
|
|||
%{_datadir}/dbus-1/system-services/org.freedesktop.Accounts.service
|
||||
%{_datadir}/polkit-1/actions/org.freedesktop.accounts.policy
|
||||
%{_datadir}/accountsservice/interfaces/com.redhat.AccountsServiceUser.System.xml
|
||||
%{_datadir}/accountsservice/user-templates/administrator
|
||||
%{_datadir}/accountsservice/user-templates/standard
|
||||
%{_datadir}/dbus-1/interfaces/com.redhat.AccountsServiceUser.System.xml
|
||||
%dir %{_localstatedir}/lib/AccountsService/
|
||||
%dir %{_localstatedir}/lib/AccountsService/users
|
||||
|
@ -107,6 +119,10 @@ files needed to build applications that use accountsservice-libs.
|
|||
%{_datadir}/gtk-doc/html/libaccountsservice/*
|
||||
|
||||
%changelog
|
||||
* Wed Aug 04 2021 Ray Strode <rstrode@redhat.com> - 0.6.55-2
|
||||
- Add support for user templates so user can specify default session
|
||||
Resolves: #1812788
|
||||
|
||||
* Fri Jan 15 2021 Ray Strode <rstrode@redhat.com> - 0.6.55-1
|
||||
- Rebase to 0.6.55
|
||||
Resolves: #1846376
|
||||
|
|
Loading…
Reference in New Issue