#include <gio/gio.h>
#include <sys/stat.h>
#include <errno.h>
+#include <glib/gprintf.h>
+#include <glib/gstdio.h>
#include "gumd-daemon-user.h"
#include "gumd-daemon-group.h"
#include "common/gum-error.h"
#include "common/gum-utils.h"
+struct _userinfo {
+ char *icon;
+};
+
struct _GumdDaemonUserPrivate
{
GumConfig *config;
* 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)
GUMD_TYPE_DAEMON_USER, GumdDaemonUserPrivate)
#define GUMD_DAY (24L*3600L)
+#define GUMD_STR_LEN 4096
enum
{
PROP_HOMEPHONE,
PROP_HOMEDIR,
PROP_SHELL,
+ PROP_ICON,
N_PROPERTIES
};
}
}
+static void
+_free_info_entry (
+ struct _userinfo *info)
+{
+ if (info) {
+ g_free (info->icon);
+ }
+}
+
static GumUserType
_get_usertype_from_gecos (
struct passwd *pw)
}
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,
_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);
}
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);
}
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);
}
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
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);
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,
{
struct passwd *pent = NULL;
struct spwd *spent = NULL;
+ struct _userinfo info = {0,};
DBG("");
if ((pent = _get_passwd (self, error)) == NULL) {
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);
/*shadow entry*/
_copy_shadow_struct (spent, self->priv->shadow, FALSE);
+ /*userinfo entry*/
+ _copy_userinfo_struct (&info, self);
+
return TRUE;
}
return FALSE;
}
+ _add_userinfo(self);
+
if (!_set_default_groups (self, error) ||
!_create_home_dir (self, error)) {
gum_lock_pwdf_unlock ();
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;
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,
{
struct passwd *pw = NULL;
struct spwd *shadow = NULL;
+ struct _userinfo info = {0,};
gchar *old_name = NULL;
gint change = 0;
"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);
gchar *home_dir;
gchar *shell;
gchar *secret;
+ gchar *icon;
} InputUser;
typedef struct {
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);
}
}
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
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);
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);
"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,
"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 }
};