From efad2fba46e616ce5c34e4e5c5f2e169737f18b4 Mon Sep 17 00:00:00 2001 From: Minkyu Kang Date: Mon, 16 Feb 2015 14:58:07 +0900 Subject: [PATCH] Adds support the icon property The Icon property will be saved at /var/lib/gumd/user/[uid] file This file follow .ini file format [User] Icon=/usr/share/icons/user.png So if we need to add new properties, this file can be expanded easily Change-Id: I17f8ce3eb5f8a0e834678c3cca74a2a69cd87a97 Signed-off-by: Minkyu Kang --- data/tizen/etc/gumd/gumd-tizen-common.conf | 3 + include/gum/common/gum-config-general.h | 8 + packaging/gumd.spec | 1 + ...rg.O1.SecurityAccounts.gUserManagement.User.xml | 6 + src/daemon/core/gumd-daemon-user.c | 208 +++++++++++++++++++++ src/lib/gum-user.c | 11 ++ src/utils/gumd-utils.c | 13 +- 7 files changed, 248 insertions(+), 2 deletions(-) diff --git a/data/tizen/etc/gumd/gumd-tizen-common.conf b/data/tizen/etc/gumd/gumd-tizen-common.conf index a915ad4..71826d4 100644 --- a/data/tizen/etc/gumd/gumd-tizen-common.conf +++ b/data/tizen/etc/gumd/gumd-tizen-common.conf @@ -65,6 +65,9 @@ DEFAULT_USR_GROUPS=audio,video,display # environment variable. SKEL_DIR=/etc/skel +# Path to user information folder. +USERINFO_DIR=/var/lib/gumd/user/ + # Minimum value for the automatic uid selection. Default value is: 1000 UID_MIN=5001 diff --git a/include/gum/common/gum-config-general.h b/include/gum/common/gum-config-general.h index 1ee49bb..7a8f3f2 100644 --- a/include/gum/common/gum-config-general.h +++ b/include/gum/common/gum-config-general.h @@ -158,6 +158,14 @@ "/SKEL_DIR" /** + * GUM_CONFIG_GENERAL_USERINFO_DIR: + * + * Path to user information folder. + */ +#define GUM_CONFIG_GENERAL_USERINFO_DIR GUM_CONFIG_GENERAL \ + "/USERINFO_DIR" + +/** * GUM_CONFIG_GENERAL_UID_MIN: * * Minimum value for the automatic uid selection. Default value is: 2000 diff --git a/packaging/gumd.spec b/packaging/gumd.spec index be72810..c3bc696 100644 --- a/packaging/gumd.spec +++ b/packaging/gumd.spec @@ -108,6 +108,7 @@ install -d -m 755 %{_sysconfdir}/%{name}/useradd.d install -d -m 755 %{_sysconfdir}/%{name}/userdel.d install -d -m 755 %{_sysconfdir}/%{name}/groupadd.d install -d -m 755 %{_sysconfdir}/%{name}/groupdel.d +install -d -m 755 %{_localstatedir}/lib/%{name}/user %postun -p /sbin/ldconfig diff --git a/src/common/dbus/interfaces/org.O1.SecurityAccounts.gUserManagement.User.xml b/src/common/dbus/interfaces/org.O1.SecurityAccounts.gUserManagement.User.xml index 4aa2e42..f2ebab0 100644 --- a/src/common/dbus/interfaces/org.O1.SecurityAccounts.gUserManagement.User.xml +++ b/src/common/dbus/interfaces/org.O1.SecurityAccounts.gUserManagement.User.xml @@ -137,5 +137,11 @@ + + path of the user icon + + + diff --git a/src/daemon/core/gumd-daemon-user.c b/src/daemon/core/gumd-daemon-user.c index 24fcbb7..3805c9f 100644 --- a/src/daemon/core/gumd-daemon-user.c +++ b/src/daemon/core/gumd-daemon-user.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include "gumd-daemon-user.h" #include "gumd-daemon-group.h" @@ -45,6 +47,10 @@ #include "common/gum-error.h" #include "common/gum-utils.h" +struct _userinfo { + char *icon; +}; + struct _GumdDaemonUserPrivate { GumConfig *config; @@ -63,6 +69,11 @@ struct _GumdDaemonUserPrivate * account_expiry_date:reserved_field */ struct spwd *shadow; + + /* user info file entries format: + * icon: + */ + struct _userinfo *info; }; G_DEFINE_TYPE (GumdDaemonUser, gumd_daemon_user, G_TYPE_OBJECT) @@ -71,6 +82,7 @@ G_DEFINE_TYPE (GumdDaemonUser, gumd_daemon_user, G_TYPE_OBJECT) GUMD_TYPE_DAEMON_USER, GumdDaemonUserPrivate) #define GUMD_DAY (24L*3600L) +#define GUMD_STR_LEN 4096 enum { @@ -89,6 +101,7 @@ enum PROP_HOMEPHONE, PROP_HOMEDIR, PROP_SHELL, + PROP_ICON, N_PROPERTIES }; @@ -131,6 +144,15 @@ _free_shadow_entry ( } } +static void +_free_info_entry ( + struct _userinfo *info) +{ + if (info) { + g_free (info->icon); + } +} + static GumUserType _get_usertype_from_gecos ( struct passwd *pw) @@ -344,6 +366,19 @@ _set_shell_property ( } static void +_set_icon_property ( + GumdDaemonUser *self, + const gchar *value) +{ + if (g_strcmp0 (value, self->priv->info->icon) != 0 && + gum_validate_db_string_entry (value, NULL)) { + GUM_STR_FREE (self->priv->info->icon); + self->priv->info->icon = g_strdup (value); + g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_ICON]); + } +} + +static void _set_property ( GObject *object, guint property_id, @@ -405,6 +440,10 @@ _set_property ( _set_shell_property (self, g_value_get_string (value)); break; } + case PROP_ICON: { + _set_icon_property (self, g_value_get_string (value)); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -503,6 +542,10 @@ _get_property ( g_value_set_string (value, self->priv->pw->pw_shell); break; } + case PROP_ICON: { + g_value_set_string (value, self->priv->info->icon); + break; + } default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); } @@ -537,6 +580,11 @@ _finalize (GObject *object) self->priv->pw = NULL; } + if (self->priv->info) { + _free_info_entry (self->priv->info); + self->priv->info = NULL; + } + G_OBJECT_CLASS (gumd_daemon_user_parent_class)->finalize (object); } @@ -551,6 +599,7 @@ gumd_daemon_user_init ( self->priv->pw->pw_uid = GUM_USER_INVALID_UID; self->priv->pw->pw_gid = GUMD_DAEMON_GROUP_INVALID_GID; self->priv->shadow = g_malloc0 (sizeof (struct spwd)); + self->priv->info = g_malloc0 (sizeof (struct _userinfo)); } static void @@ -664,6 +713,13 @@ gumd_daemon_user_class_init ( G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + properties[PROP_ICON] = g_param_spec_string ("icon", + "Icon", + "Icon path of User", + "" /* default value */, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPERTIES, properties); @@ -1237,6 +1293,137 @@ _finished: return deleted; } +static gboolean +_get_userinfo_path(GumdDaemonUser *self, gchar *path, gulong n) +{ + const gchar *str = NULL; + + str = gum_config_get_string (self->priv->config, GUM_CONFIG_GENERAL_USERINFO_DIR); + if (!str) { + WARN("Failed to get userinfo file path"); + return FALSE; + } + + g_snprintf(path, n, "%s%d", str, self->priv->pw->pw_uid); + + return TRUE; +} + +static void +_delete_userinfo(GumdDaemonUser *self) +{ + gchar path[GUMD_STR_LEN]; + + if (!_get_userinfo_path(self, path, sizeof(path))) + return; + + g_remove(path); +} + +static gboolean +_add_userinfo(GumdDaemonUser *self) +{ + GKeyFile *key = NULL; + GError *error = NULL; + gchar path[GUMD_STR_LEN]; + + key = g_key_file_new(); + if (!key) + return FALSE; + + if (self->priv->info->icon) + g_key_file_set_string(key, "User", "Icon", self->priv->info->icon); + + if (!_get_userinfo_path(self, path, sizeof(path))) + return FALSE; + + if (!g_key_file_save_to_file(key, path, &error)) { + WARN("Key file save failure error %d:%s", error ? error->code : 0, + error ? error->message : ""); + g_key_file_free(key); + g_clear_error(&error); + return FALSE; + } + + g_key_file_free(key); + + return TRUE; +} + +static gboolean +_update_userinfo(GumdDaemonUser *self, struct _userinfo *info) +{ + GKeyFile *key = NULL; + GError *error = NULL; + gchar path[GUMD_STR_LEN]; + + key = g_key_file_new(); + if (!key) + return FALSE; + + if (!_get_userinfo_path(self, path, sizeof(path))) + return FALSE; + + g_key_file_load_from_file(key, path, G_KEY_FILE_NONE, NULL); + + if (info->icon) + g_key_file_set_string(key, "User", "Icon", info->icon); + + if (!g_key_file_save_to_file(key, path, &error)) { + WARN("Key file save failure error %d:%s", error ? error->code : 0, + error ? error->message : ""); + g_key_file_free(key); + g_clear_error(&error); + return FALSE; + } + + g_key_file_free(key); + + return TRUE; +} + +static gboolean +_get_userinfo(GumdDaemonUser *self, struct _userinfo *info) +{ + GKeyFile *key = NULL; + GError *error = NULL; + gchar path[GUMD_STR_LEN]; + + key = g_key_file_new(); + if (!key) + return FALSE; + + if (!_get_userinfo_path(self, path, sizeof(path))) + return FALSE; + + if (!g_key_file_load_from_file(key, path, G_KEY_FILE_NONE, &error)) { + g_key_file_free(key); + g_clear_error(&error); + return FALSE; + } + + info->icon = g_key_file_get_string(key, "User", "Icon", NULL); + if (!info->icon) + info->icon = ""; + + g_key_file_free(key); + + return TRUE; +} + +static gboolean +_copy_userinfo_struct ( + struct _userinfo *src, + GumdDaemonUser *dest) +{ + if (!src || !dest) + return FALSE; + + _set_icon_property (dest, src->icon); + + return TRUE; +} + static struct passwd * _get_passwd ( GumdDaemonUser *self, @@ -1320,6 +1507,7 @@ _copy_passwd_data ( { struct passwd *pent = NULL; struct spwd *spent = NULL; + struct _userinfo info = {0,}; DBG(""); if ((pent = _get_passwd (self, error)) == NULL) { @@ -1331,6 +1519,7 @@ _copy_passwd_data ( GUM_RETURN_WITH_ERROR (GUM_ERROR_USER_NOT_FOUND, "User not found", error, FALSE); } + _get_userinfo (self, &info); /*passwd entry*/ _copy_passwd_struct (pent, self); @@ -1338,6 +1527,9 @@ _copy_passwd_data ( /*shadow entry*/ _copy_shadow_struct (spent, self->priv->shadow, FALSE); + /*userinfo entry*/ + _copy_userinfo_struct (&info, self); + return TRUE; } @@ -1546,6 +1738,8 @@ gumd_daemon_user_add ( return FALSE; } + _add_userinfo(self); + if (!_set_default_groups (self, error) || !_create_home_dir (self, error)) { gum_lock_pwdf_unlock (); @@ -1568,6 +1762,7 @@ gumd_daemon_user_add ( gum_utils_run_user_scripts (scrip_dir, self->priv->pw->pw_name, self->priv->pw->pw_uid, self->priv->pw->pw_gid, self->priv->pw->pw_dir, ut); + g_free (ut); gum_lock_pwdf_unlock (); return TRUE; @@ -1650,6 +1845,8 @@ gumd_daemon_user_delete ( self->priv->pw->pw_uid, self->priv->pw->pw_gid, self->priv->pw->pw_dir, NULL); + _delete_userinfo(self); + if (!gum_file_update (G_OBJECT (self), GUM_OPTYPE_DELETE, (GumFileUpdateCB)_update_passwd_entry, gum_config_get_string (self->priv->config, @@ -1731,6 +1928,7 @@ gumd_daemon_user_update ( { struct passwd *pw = NULL; struct spwd *shadow = NULL; + struct _userinfo info = {0,}; gchar *old_name = NULL; gint change = 0; @@ -1761,6 +1959,16 @@ gumd_daemon_user_update ( "User not found in Shadow", error, FALSE); } + /* userinfo entry */ + _get_userinfo (self, &info); + + if (self->priv->info->icon && g_strcmp0 (info.icon, self->priv->info->icon)) { + change++; + info.icon = self->priv->info->icon; + } + if (change) + _update_userinfo(self, &info); + /* shadow entry */ _copy_shadow_struct (shadow, self->priv->shadow, TRUE); diff --git a/src/lib/gum-user.c b/src/lib/gum-user.c index ccb88b1..9313479 100644 --- a/src/lib/gum-user.c +++ b/src/lib/gum-user.c @@ -144,6 +144,7 @@ enum PROP_HOMEDIR, PROP_SHELL, PROP_OFFLINE, + PROP_ICON, N_PROPERTIES }; @@ -521,6 +522,16 @@ gum_user_class_init ( FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + /** + * GumUser:icon: + */ + properties[PROP_ICON] = g_param_spec_string ("icon", + "Icon", + "Icon path of User", + "" /* default value */, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, N_PROPERTIES, properties); } diff --git a/src/utils/gumd-utils.c b/src/utils/gumd-utils.c index 5ab3629..c18d03b 100644 --- a/src/utils/gumd-utils.c +++ b/src/utils/gumd-utils.c @@ -53,6 +53,7 @@ typedef struct { gchar *home_dir; gchar *shell; gchar *secret; + gchar *icon; } InputUser; typedef struct { @@ -94,6 +95,7 @@ _free_test_user ( g_free (user->office); g_free (user->office_phone); g_free (user->home_phone); g_free (user->home_dir); g_free (user->shell); g_free (user->user_type); + g_free (user->icon); g_free (user); } } @@ -133,6 +135,9 @@ _set_user_update_prop ( if (user->secret) { g_object_set (G_OBJECT (guser), "secret", user->secret, NULL); } + if (user->icon) { + g_object_set (G_OBJECT (guser), "icon", user->icon, NULL); + } } static void @@ -177,6 +182,7 @@ _print_user_prop ( g_object_get (G_OBJECT (guser), "homephone", &user->home_phone, NULL); g_object_get (G_OBJECT (guser), "homedir", &user->home_dir, NULL); g_object_get (G_OBJECT (guser), "shell", &user->shell, NULL); + g_object_get (G_OBJECT (guser), "icon", &user->icon, NULL); INFO ("uid : %u", user->uid); INFO ("gid : %u", user->gid); @@ -189,6 +195,7 @@ _print_user_prop ( user->office_phone ? user->office_phone : "UNKNOWN"); INFO ("homephone : %s", user->home_phone ? user->home_phone : "UNKNOWN"); INFO ("homedir : %s", user->home_dir ? user->home_dir : "UNKNOWN"); + INFO ("icon: %s", user->icon ? user->icon: "UNKNOWN"); INFO ("shell : %s\n", user->shell ? user->shell : "UNKNOWN"); _free_test_user (user); @@ -610,8 +617,8 @@ main (int argc, char *argv[]) "delete user -- uid is mandatory", NULL}, { "update-user", 'u', 0, G_OPTION_ARG_NONE, &is_user_up_op, "update user -- uid is mandatory; possible props that can be " - "updated are secret, realname, office, officephone, homephone " - "and shell", NULL}, + "updated are secret, realname, office, officephone, homephone, " + "icon and shell", NULL}, { "get-user", 'b', 0, G_OPTION_ARG_NONE, &is_user_get_op, "get user" " -- uid is mandatory", NULL}, { "get-user-by-name", 'c', 0, G_OPTION_ARG_NONE, @@ -686,6 +693,8 @@ main (int argc, char *argv[]) "dir"}, { "shell", 0, 0, G_OPTION_ARG_STRING, &user->shell, "shell path", "shell"}, + { "icon", 0, 0, G_OPTION_ARG_STRING, &user->icon, "icon path", + "icon"}, { NULL } }; -- 2.7.4