diff options
-rw-r--r-- | doc/tmpl/user.sgml | 5 | ||||
-rw-r--r-- | greeters/gtk/lightdm-example-gtk-greeter.c | 2 | ||||
-rwxr-xr-x | greeters/python-gtk/lightdm-example-python-gtk-greeter | 2 | ||||
-rw-r--r-- | liblightdm-gobject/greeter-protocol.h | 4 | ||||
-rw-r--r-- | liblightdm-gobject/greeter.c | 461 | ||||
-rw-r--r-- | liblightdm-gobject/lightdm/user.h | 2 | ||||
-rw-r--r-- | liblightdm-gobject/user-private.h | 6 | ||||
-rw-r--r-- | liblightdm-gobject/user.c | 61 | ||||
-rw-r--r-- | liblightdm-qt/Makefile.am | 17 | ||||
-rw-r--r-- | liblightdm-qt/ldmgreeter.cpp | 17 | ||||
-rw-r--r-- | liblightdm-qt/user-manager.xml | 21 | ||||
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/greeter-protocol.h | 4 | ||||
-rw-r--r-- | src/greeter.c | 70 | ||||
-rw-r--r-- | src/lightdm.c | 154 | ||||
-rw-r--r-- | src/user-manager.c | 400 | ||||
-rw-r--r-- | src/user-manager.h | 61 |
17 files changed, 451 insertions, 838 deletions
diff --git a/doc/tmpl/user.sgml b/doc/tmpl/user.sgml index 9fc94acf..2ca73579 100644 --- a/doc/tmpl/user.sgml +++ b/doc/tmpl/user.sgml @@ -52,6 +52,11 @@ A user has the following properties: </para> +<!-- ##### ARG LdmUser:home-directory ##### --> +<para> + +</para> + <!-- ##### ARG LdmUser:image ##### --> <para> diff --git a/greeters/gtk/lightdm-example-gtk-greeter.c b/greeters/gtk/lightdm-example-gtk-greeter.c index d697931a..a1eb95a3 100644 --- a/greeters/gtk/lightdm-example-gtk-greeter.c +++ b/greeters/gtk/lightdm-example-gtk-greeter.c @@ -516,7 +516,7 @@ connect_cb (LdmGreeter *greeter) GdkPixbuf *pixbuf = NULL; image = ldm_user_get_image (user); - if (strcmp (image, "") == 0) + if (image) { gchar *path; diff --git a/greeters/python-gtk/lightdm-example-python-gtk-greeter b/greeters/python-gtk/lightdm-example-python-gtk-greeter index d7c9aba2..3edbb91e 100755 --- a/greeters/python-gtk/lightdm-example-python-gtk-greeter +++ b/greeters/python-gtk/lightdm-example-python-gtk-greeter @@ -196,7 +196,7 @@ class Greeter: for user in users: image = user.get_image() pixbuf = None - if image != '': + if image != None: path = GLib.filename_from_uri(image) pixbuf = GdkPixbuf.Pixbuf.new_from_file_at_scale(path, 64, 64, True) model.append((user.get_name(), user.get_display_name(), pixbuf, True)) diff --git a/liblightdm-gobject/greeter-protocol.h b/liblightdm-gobject/greeter-protocol.h index 3a9c6dd7..c72fc636 100644 --- a/liblightdm-gobject/greeter-protocol.h +++ b/liblightdm-gobject/greeter-protocol.h @@ -20,12 +20,14 @@ typedef enum GREETER_MESSAGE_CONTINUE_AUTHENTICATION = 3, GREETER_MESSAGE_LOGIN = 4, GREETER_MESSAGE_CANCEL_AUTHENTICATION = 5, + GREETER_MESSAGE_GET_USER_DEFAULTS = 6, /* Messages from the server to the greeter */ GREETER_MESSAGE_CONNECTED = 101, GREETER_MESSAGE_QUIT = 102, GREETER_MESSAGE_PROMPT_AUTHENTICATION = 103, - GREETER_MESSAGE_END_AUTHENTICATION = 104 + GREETER_MESSAGE_END_AUTHENTICATION = 104, + GREETER_MESSAGE_USER_DEFAULTS = 106 } GreeterMessage; #endif /* _GREETER_PROTOCOL_H_ */ diff --git a/liblightdm-gobject/greeter.c b/liblightdm-gobject/greeter.c index 34af0cdd..5a7e73cb 100644 --- a/liblightdm-gobject/greeter.c +++ b/liblightdm-gobject/greeter.c @@ -10,10 +10,11 @@ */ #include <stdlib.h> +#include <errno.h> #include <string.h> #include <locale.h> #include <sys/utsname.h> - +#include <pwd.h> #include <gio/gdesktopappinfo.h> #include <security/pam_appl.h> #include <libxklavier/xklavier.h> @@ -64,7 +65,7 @@ struct _LdmGreeterPrivate GDBusConnection *system_bus; - GDBusProxy *session_proxy, *user_proxy; + GDBusProxy *lightdm_proxy; GIOChannel *to_server_channel, *from_server_channel; gchar *read_buffer; @@ -74,10 +75,19 @@ struct _LdmGreeterPrivate gchar *hostname; + /* Configuration file */ + GKeyFile *config; + gchar *theme; GKeyFile *theme_file; + /* File monitor for password file */ + GFileMonitor *passwd_monitor; + + /* TRUE if have scanned users */ gboolean have_users; + + /* List of users */ GList *users; gboolean have_languages; @@ -254,32 +264,36 @@ handle_prompt_authentication (LdmGreeter *greeter, gsize *offset) } static gboolean -from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data) +read_packet (LdmGreeter *greeter, gboolean block) { - LdmGreeter *greeter = data; - gsize n_to_read, n_read, offset; - GIOStatus status; - guint32 id, return_code; + gsize n_to_read, n_read; GError *error = NULL; + /* Read the header, or the whole packet if we already have that */ n_to_read = HEADER_SIZE; if (greeter->priv->n_read >= HEADER_SIZE) n_to_read += get_packet_length (greeter); - status = g_io_channel_read_chars (greeter->priv->from_server_channel, - greeter->priv->read_buffer + greeter->priv->n_read, - n_to_read - greeter->priv->n_read, - &n_read, - &error); - if (status != G_IO_STATUS_NORMAL) - g_warning ("Error reading from server: %s", error->message); - g_clear_error (&error); - if (status != G_IO_STATUS_NORMAL) - return TRUE; + do + { + GIOStatus status; + status = g_io_channel_read_chars (greeter->priv->from_server_channel, + greeter->priv->read_buffer + greeter->priv->n_read, + n_to_read - greeter->priv->n_read, + &n_read, + &error); + if (status == G_IO_STATUS_ERROR) + g_warning ("Error reading from server: %s", error->message); + g_clear_error (&error); + if (status != G_IO_STATUS_NORMAL) + break; + + greeter->priv->n_read += n_read; + } while (greeter->priv->n_read < n_to_read && block); - greeter->priv->n_read += n_read; + /* Stop if haven't got all the data we want */ if (greeter->priv->n_read != n_to_read) - return TRUE; + return FALSE; /* If have header, rerun for content */ if (greeter->priv->n_read == HEADER_SIZE) @@ -288,10 +302,23 @@ from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data) if (n_to_read > 0) { greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read); - return from_server_cb (source, condition, data); + return read_packet (greeter, block); } } + return TRUE; +} + +static gboolean +from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data) +{ + LdmGreeter *greeter = data; + gsize offset; + guint32 id, return_code; + + if (!read_packet (greeter, FALSE)) + return TRUE; + offset = 0; id = read_int (greeter, &offset); read_int (greeter, &offset); @@ -400,20 +427,13 @@ ldm_greeter_connect_to_server (LdmGreeter *greeter) g_io_channel_set_encoding (greeter->priv->from_server_channel, NULL, NULL); g_io_add_watch (greeter->priv->from_server_channel, G_IO_IN, from_server_cb, greeter); - greeter->priv->session_proxy = g_dbus_proxy_new_sync (greeter->priv->lightdm_bus, + greeter->priv->lightdm_proxy = g_dbus_proxy_new_sync (greeter->priv->lightdm_bus, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.lightdm.LightDisplayManager", - "/org/lightdm/LightDisplayManager/Session", - "org.lightdm.LightDisplayManager.Session", + "/org/lightdm/LightDisplayManager", + "org.lightdm.LightDisplayManager", NULL, NULL); - greeter->priv->user_proxy = g_dbus_proxy_new_sync (greeter->priv->lightdm_bus, - G_DBUS_PROXY_FLAGS_NONE, - NULL, - "org.lightdm.LightDisplayManager", - "/org/lightdm/LightDisplayManager/Users", - "org.lightdm.LightDisplayManager.Users", - NULL, NULL); g_debug ("Connecting to display manager..."); write_header (greeter, GREETER_MESSAGE_CONNECT, 0); @@ -563,160 +583,264 @@ get_user_by_name (LdmGreeter *greeter, const gchar *username) return NULL; } +static gint +compare_user (gconstpointer a, gconstpointer b) +{ + LdmUser *user_a = (LdmUser *) a, *user_b = (LdmUser *) b; + return strcmp (ldm_user_get_display_name (user_a), ldm_user_get_display_name (user_b)); +} + static void -user_changed_cb (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) -{ - LdmGreeter *greeter = user_data; - gchar *username, *real_name, *image; - gboolean logged_in; - LdmUser *user; - - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sssb)"))) +load_config (LdmGreeter *greeter) +{ + GVariant *result; + const gchar *config_path = NULL; + + if (greeter->priv->config) + return; + + result = g_dbus_proxy_get_cached_property (greeter->priv->lightdm_proxy, + "ConfigFile"); + if (!result) { - g_warning ("Unknown type in %s signal", signal_name); + g_warning ("No ConfigFile property"); return; } - g_variant_get (parameters, "(sssb)", &username, &real_name, &image, &logged_in); + if (g_variant_is_of_type (result, G_VARIANT_TYPE_STRING)) + config_path = g_variant_get_string (result, NULL); + else + g_warning ("Invalid type for config file: %s, expected string", g_variant_get_type_string (result)); - user = get_user_by_name (greeter, username); - if (user) + if (config_path) { - g_debug ("User %s changed", username); - ldm_user_set_real_name (user, real_name); - ldm_user_set_image (user, image); - ldm_user_set_logged_in (user, logged_in); - g_signal_emit (greeter, signals[USER_CHANGED], 0, user); + GError *error = NULL; + + g_debug ("Loading config from %s", config_path); + + greeter->priv->config = g_key_file_new (); + if (!g_key_file_load_from_file (greeter->priv->config, config_path, G_KEY_FILE_NONE, &error)) + g_warning ("Failed to load configuration from %s: %s", config_path, error->message); // FIXME: Don't make warning on no file, just info + g_clear_error (&error); } + + g_variant_unref (result); +} + +static void +load_users (LdmGreeter *greeter) +{ + gchar **hidden_users, **hidden_shells; + gchar *value; + gint minimum_uid; + GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link; + + load_config (greeter); + + if (g_key_file_has_key (greeter->priv->config, "UserManager", "minimum-uid", NULL)) + minimum_uid = g_key_file_get_integer (greeter->priv->config, "UserManager", "minimum-uid", NULL); else + minimum_uid = 500; + + value = g_key_file_get_string (greeter->priv->config, "UserManager", "hidden-users", NULL); + if (!value) + value = g_strdup ("nobody nobody4 noaccess"); + hidden_users = g_strsplit (value, " ", -1); + g_free (value); + + value = g_key_file_get_string (greeter->priv->config, "UserManager", "hidden-shells", NULL); + if (!value) + value = g_strdup ("/bin/false /usr/sbin/nologin"); + hidden_shells = g_strsplit (value, " ", -1); + g_free (value); + + setpwent (); + + while (TRUE) { - g_debug ("User %s added", username); - user = ldm_user_new (greeter, username, real_name, image, logged_in); - greeter->priv->users = g_list_append (greeter->priv->users, user); - g_signal_emit (greeter, signals[USER_ADDED], 0, user); + struct passwd *entry; + LdmUser *user; + char **tokens; + gchar *real_name, *image_path, *image; + int i; + + errno = 0; + entry = getpwent (); + if (!entry) + break; + + /* Ignore system users */ + if (entry->pw_uid < minimum_uid) + continue; + + /* Ignore users disabled by shell */ + if (entry->pw_shell) + { + for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++); + if (hidden_shells[i]) + continue; + } + + /* Ignore certain users */ + for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++); + if (hidden_users[i]) + continue; + + tokens = g_strsplit (entry->pw_gecos, ",", -1); + if (tokens[0] != NULL && tokens[0][0] != '\0') + real_name = g_strdup (tokens[0]); + else + real_name = NULL; + g_strfreev (tokens); + + image_path = g_build_filename (entry->pw_dir, ".face", NULL); + if (!g_file_test (image_path, G_FILE_TEST_EXISTS)) + { + g_free (image_path); + image_path = g_build_filename (entry->pw_dir, ".face.icon", NULL); + if (!g_file_test (image_path, G_FILE_TEST_EXISTS)) + { + g_free (image_path); + image_path = NULL; + } + } + if (image_path) + image = g_filename_to_uri (image_path, NULL, NULL); + else + image = NULL; + g_free (image_path); + + user = ldm_user_new (greeter, entry->pw_name, real_name, entry->pw_dir, image, FALSE); + g_free (real_name); + g_free (image); + + /* Update existing users if have them */ + for (link = greeter->priv->users; link; link = link->next) + { + LdmUser *info = link->data; + if (strcmp (ldm_user_get_name (info), ldm_user_get_name (user)) == 0) + { + // FIXME: Use changed signal from user object? + if (g_strcmp0 (ldm_user_get_real_name (info), ldm_user_get_real_name (user)) != 0 || + g_strcmp0 (ldm_user_get_image (info), ldm_user_get_image (user)) != 0 || + g_strcmp0 (ldm_user_get_home_directory (info), ldm_user_get_home_directory (user)) != 0 || + ldm_user_get_logged_in (info) != ldm_user_get_logged_in (user)) + { + ldm_user_set_real_name (info, ldm_user_get_real_name (user)); + ldm_user_set_image (info, ldm_user_get_image (user)); + ldm_user_set_home_directory (info, ldm_user_get_home_directory (user)); + ldm_user_set_logged_in (info, ldm_user_get_logged_in (user)); + g_object_unref (user); + user = info; + changed_users = g_list_insert_sorted (changed_users, user, compare_user); + } + else + { + g_object_unref (user); + user = info; + } + break; + } + } + if (!link) + { + /* Only notify once we have loaded the user list */ + if (greeter->priv->have_users) + new_users = g_list_insert_sorted (new_users, user, compare_user); + } + users = g_list_insert_sorted (users, user, compare_user); } + g_strfreev (hidden_users); + g_strfreev (hidden_shells); - g_free (username); - g_free (real_name); - g_free (image); -} + if (errno != 0) + g_warning ("Failed to read password database: %s", strerror (errno)); -static void -user_removed_cb (GDBusConnection *connection, - const gchar *sender_name, - const gchar *object_path, - const gchar *interface_name, - const gchar *signal_name, - GVariant *parameters, - gpointer user_data) -{ - LdmGreeter *greeter = user_data; - gchar *username; - LdmUser *user; - - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)"))) + endpwent (); + + /* Use new user list */ + old_users = greeter->priv->users; + greeter->priv->users = users; + + /* Notify of changes */ + for (link = new_users; link; link = link->next) { - g_warning ("Unknown type in %s signal", signal_name); - return; + LdmUser *info = link->data; + g_debug ("User %s added", ldm_user_get_name (info)); + g_signal_emit (greeter, signals[USER_ADDED], 0, info); + } + g_list_free (new_users); + for (link = changed_users; link; link = link->next) + { + LdmUser *info = link->data; + g_debug ("User %s changed", ldm_user_get_name (info)); + g_signal_emit (greeter, signals[USER_CHANGED], 0, info); } + g_list_free (changed_users); + for (link = old_users; link; link = link->next) + { + GList *new_link; - g_variant_get (parameters, "(s)", &username); + /* See if this user is in the current list */ + for (new_link = greeter->priv->users; new_link; new_link = new_link->next) + { + if (new_link->data == link->data) + break; + } - user = get_user_by_name (greeter, username); - if (user) - { - g_debug ("User %s removed", username); - greeter->priv->users = g_list_remove (greeter->priv->users, user); - g_signal_emit (greeter, signals[USER_REMOVED], 0, user); - g_object_unref (user); + if (!new_link) + { + LdmUser *info = link->data; + g_debug ("User %s removed", ldm_user_get_name (info)); + g_signal_emit (greeter, signals[USER_REMOVED], 0, info); + g_object_unref (info); + } } + g_list_free (old_users); +} - g_free (username); +static void +passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, LdmGreeter *greeter) +{ + if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) + { + g_debug ("%s changed, reloading user list", g_file_get_path (file)); + load_users (greeter); + } } static void update_users (LdmGreeter *greeter) { - GVariant *result, *user_array; - GVariantIter iter; - gchar *name, *real_name, *image; - gboolean logged_in; + GFile *passwd_file; GError *error = NULL; if (greeter->priv->have_users) return; - g_dbus_connection_signal_subscribe (greeter->priv->lightdm_bus, - "org.lightdm.LightDisplayManager", - "org.lightdm.LightDisplayManager.Users", - "UserAdded", - "/org/lightdm/LightDisplayManager/Users", - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - user_changed_cb, - greeter, - NULL); - g_dbus_connection_signal_subscribe (greeter->priv->lightdm_bus, - "org.lightdm.LightDisplayManager", - "org.lightdm.LightDisplayManager.Users", - "UserChanged", - "/org/lightdm/LightDisplayManager/Users", - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - user_changed_cb, - greeter, - NULL); - g_dbus_connection_signal_subscribe (greeter->priv->lightdm_bus, - "org.lightdm.LightDisplayManager", - "org.lightdm.LightDisplayManager.Users", - "UserRemoved", - "/org/lightdm/LightDisplayManager/Users", - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - user_removed_cb, - greeter, - NULL); - - g_debug ("Getting user list..."); - result = g_dbus_proxy_call_sync (greeter->priv->user_proxy, - "GetUsers", - NULL, - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (!result) - g_warning ("Failed to get users: %s", error->message); - g_clear_error (&error); - if (!result) - return; + load_config (greeter); - if (!g_variant_is_of_type (result, G_VARIANT_TYPE ("(a(sssb))"))) + /* User listing is disabled */ + if (g_key_file_has_key (greeter->priv->config, "UserManager", "load-users", NULL) && + !g_key_file_get_boolean (greeter->priv->config, "UserManager", "load-users", NULL)) { - g_warning ("Unknown type returned"); - g_variant_unref (result); + greeter->priv->have_users = TRUE; return; } - user_array = g_variant_get_child_value (result, 0); - g_debug ("Got %zi users", g_variant_n_children (user_array)); - g_variant_iter_init (&iter, user_array); - while (g_variant_iter_next (&iter, "(&s&s&sb)", &name, &real_name, &image, &logged_in)) - { - LdmUser *user; - user = ldm_user_new (greeter, name, real_name, image, logged_in); - greeter->priv->users = g_list_append (greeter->priv->users, user); - } + load_users (greeter); - greeter->priv->have_users = TRUE; + /* Watch for changes to user list */ + passwd_file = g_file_new_for_path ("/etc/passwd"); + greeter->priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error); + g_object_unref (passwd_file); + if (!greeter->priv->passwd_monitor) + g_warning ("Error monitoring /etc/passwd: %s", error->message); + else + g_signal_connect (greeter->priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), greeter); + g_clear_error (&error); - g_variant_unref (result); + greeter->priv->have_users = TRUE; } /** @@ -1466,37 +1590,34 @@ ldm_greeter_shutdown (LdmGreeter *greeter) gboolean ldm_greeter_get_user_defaults (LdmGreeter *greeter, const gchar *username, gchar **language, gchar **layout, gchar **session) { - GError *error = NULL; - GVariant *result; - gboolean got_defaults = FALSE; + gsize offset = 0; + guint32 id; g_return_val_if_fail (LDM_IS_GREETER (greeter), FALSE); g_return_val_if_fail (username != NULL, FALSE); - result = g_dbus_proxy_call_sync (greeter->priv->user_proxy, - "GetUserDefaults", - g_variant_new ("(s)", username), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - - if (!result) - g_warning ("Failed to get user defaults: %s", error->message); - g_clear_error (&error); - - if (!result) - return FALSE; + write_header (greeter, GREETER_MESSAGE_GET_USER_DEFAULTS, string_length (username)); + write_string (greeter, username); + flush (greeter); - if (g_variant_is_of_type (result, G_VARIANT_TYPE ("(sss)"))) + if (!read_packet (greeter, TRUE)) { - g_variant_get (result, "(sss)", language, layout, session); - got_defaults = TRUE; + g_warning ("Error reading user defaults from server"); + return FALSE; } - g_variant_unref (result); + id = read_int (greeter, &offset); + g_assert (id == GREETER_MESSAGE_USER_DEFAULTS); + read_int (greeter, &offset); + *language = read_string (greeter, &offset); + *layout = read_string (greeter, &offset); + *session = read_string (greeter, &offset); - return got_defaults; + g_debug ("User defaults for %s: language=%s, layout=%s, session=%s", username, *language, *layout, *session); + + greeter->priv->n_read = 0; + + return TRUE; } static void diff --git a/liblightdm-gobject/lightdm/user.h b/liblightdm-gobject/lightdm/user.h index 053fb31b..c3a75b4f 100644 --- a/liblightdm-gobject/lightdm/user.h +++ b/liblightdm-gobject/lightdm/user.h @@ -47,6 +47,8 @@ const gchar *ldm_user_get_real_name (LdmUser *user); const gchar *ldm_user_get_display_name (LdmUser *user); +const gchar *ldm_user_get_home_directory (LdmUser *user); + const gchar *ldm_user_get_image (LdmUser *user); const gchar *ldm_user_get_language (LdmUser *user); diff --git a/liblightdm-gobject/user-private.h b/liblightdm-gobject/user-private.h index 2cdaa6ab..4b706048 100644 --- a/liblightdm-gobject/user-private.h +++ b/liblightdm-gobject/user-private.h @@ -4,10 +4,14 @@ #include "lightdm/greeter.h" #include "lightdm/user.h" -LdmUser *ldm_user_new (LdmGreeter *greeter, const gchar *name, const gchar *real_name, const gchar *image, gboolean logged_in); +LdmUser *ldm_user_new (LdmGreeter *greeter, const gchar *name, const gchar *real_name, const gchar *home_directory, const gchar *image, gboolean logged_in); + +void ldm_user_set_name (LdmUser *user, const gchar *name); void ldm_user_set_real_name (LdmUser *user, const gchar *real_name); +void ldm_user_set_home_directory (LdmUser *user, const gchar *home_directory); + void ldm_user_set_image (LdmUser *user, const gchar *image); void ldm_user_set_logged_in (LdmUser *user, gboolean logged_in); diff --git a/liblightdm-gobject/user.c b/liblightdm-gobject/user.c index d8e36747..32f36cda 100644 --- a/liblightdm-gobject/user.c +++ b/liblightdm-gobject/user.c @@ -17,6 +17,7 @@ enum { PROP_NAME, PROP_REAL_NAME, PROP_DISPLAY_NAME, + PROP_HOME_DIRECTORY, PROP_IMAGE, PROP_LANGUAGE, PROP_LAYOUT, @@ -30,6 +31,7 @@ struct _LdmUserPrivate gchar *name; gchar *real_name; + gchar *home_directory; gchar *image; gboolean logged_in; @@ -48,15 +50,16 @@ G_DEFINE_TYPE (LdmUser, ldm_user, G_TYPE_OBJECT); * @greeter: The greeter the user is connected to * @name: The username * @real_name: The real name of the user + * @home_directory: The home directory of the user * @image: The image URI * @logged_in: TRUE if this user is currently logged in * * Return value: the new #LdmUser **/ LdmUser * -ldm_user_new (LdmGreeter *greeter, const gchar *name, const gchar *real_name, const gchar *image, gboolean logged_in) +ldm_user_new (LdmGreeter *greeter, const gchar *name, const gchar *real_name, const gchar *home_directory, const gchar *image, gboolean logged_in) { - return g_object_new (LDM_TYPE_USER, "greeter", greeter, "name", name, "real-name", real_name, "image", image, "logged-in", logged_in, NULL); + return g_object_new (LDM_TYPE_USER, "greeter", greeter, "name", name, "real-name", real_name, "home-directory", home_directory, "image", image, "logged-in", logged_in, NULL); } /** @@ -74,6 +77,14 @@ ldm_user_get_name (LdmUser *user) return user->priv->name; } +void +ldm_user_set_name (LdmUser *user, const gchar *name) +{ + g_return_if_fail (LDM_IS_USER (user)); + g_free (user->priv->name); + user->priv->name = g_strdup (name); +} + /** * ldm_user_get_real_name: * @user: A #LdmUser @@ -110,13 +121,36 @@ ldm_user_get_display_name (LdmUser *user) { g_return_val_if_fail (LDM_IS_USER (user), NULL); - if (user->priv->real_name[0] != '\0') + if (user->priv->real_name) return user->priv->real_name; else return user->priv->name; } /** + * ldm_user_get_home_directory: + * @user: A #LdmUser + * + * Get the home directory for a user. + * + * Return value: The users home directory + */ +const gchar * +ldm_user_get_home_directory (LdmUser *user) +{ + g_return_val_if_fail (LDM_IS_USER (user), NULL); + return user->priv->home_directory; +} + +void +ldm_user_set_home_directory (LdmUser *user, const gchar *home_directory) +{ + g_return_if_fail (LDM_IS_USER (user)); + g_free (user->priv->home_directory); + user->priv->home_directory = g_strdup (home_directory); +} + +/** * ldm_user_get_image: * @user: A #LdmUser * @@ -240,16 +274,19 @@ ldm_user_set_property (GObject *object, self->priv->greeter = g_object_ref (g_value_get_object (value)); break; case PROP_NAME: - self->priv->name = g_strdup (g_value_get_string (value)); + ldm_user_set_name (self, g_value_get_string (value)); break; case PROP_REAL_NAME: - self->priv->real_name = g_strdup (g_value_get_string (value)); + ldm_user_set_real_name (self, g_value_get_string (value)); + break; + case PROP_HOME_DIRECTORY: + ldm_user_set_home_directory (self, g_value_get_string (value)); break; case PROP_IMAGE: - self->priv->image = g_strdup (g_value_get_string (value)); + ldm_user_set_image (self, g_value_get_string (value)); break; case PROP_LOGGED_IN: - self->priv->logged_in = g_value_get_boolean (value); + ldm_user_set_logged_in (self, g_value_get_boolean (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -277,6 +314,9 @@ ldm_user_get_property (GObject *object, case PROP_DISPLAY_NAME: g_value_set_string (value, ldm_user_get_display_name (self)); break; + case PROP_HOME_DIRECTORY: + g_value_set_string (value, ldm_user_get_home_directory (self)); + break; case PROP_IMAGE: g_value_set_string (value, ldm_user_get_image (self)); break; @@ -337,6 +377,13 @@ ldm_user_class_init (LdmUserClass *klass) NULL, G_PARAM_READABLE)); g_object_class_install_property(object_class, + PROP_HOME_DIRECTORY, + g_param_spec_string("home-directory", + "home-directory", + "Home directory", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property(object_class, PROP_IMAGE, g_param_spec_string("image", "image", diff --git a/liblightdm-qt/Makefile.am b/liblightdm-qt/Makefile.am index f9c10bbe..6ea1fc7f 100644 --- a/liblightdm-qt/Makefile.am +++ b/liblightdm-qt/Makefile.am @@ -1,31 +1,19 @@ lib_LTLIBRARIES = liblightdm-qt-0.la -# Generate interfaces from D-Bus definitions -INTERFACE_FILES = \ - usermanagerinterface.cpp \ - usermanagerinterface.h -usermanagerinterface.cpp usermanagerinterface.h: user-manager.xml - qdbusxml2cpp $< -i ldmuser.h -c UserManagerInterface -p usermanagerinterface - # Generate metadata for QObjects MOC_FILES = \ consolekitinterface_moc.cpp \ ldmgreeter_moc.cpp \ - powermanagementinterface_moc.cpp \ - usermanagerinterface_moc.cpp + powermanagementinterface_moc.cpp consolekitinterface_moc.cpp: consolekitinterface.h moc $< -o $@ ldmgreeter_moc.cpp: ldmgreeter.h moc $< -o $@ powermanagementinterface_moc.cpp: powermanagementinterface.h moc $< -o $@ -usermanagerinterface_moc.cpp: usermanagerinterface.h - moc $< -o $@ GENERATED_FILES = $(INTERFACE_FILES) $(MOC_FILES) -ldmgreeter.cpp: usermanagerinterface.h - liblightdm_qt_0include_HEADERS = \ ldmgreeter.h \ ldmlanguage.h \ @@ -58,9 +46,6 @@ pkgconfig_DATA = liblightdm-qt-0.pc CLEANFILES = \ $(GENERATED_FILES) -EXTRA_DIST = \ - user-manager.xml - DISTCLEANFILES = \ Makefile.in \ $(pkgconfig_DATA) diff --git a/liblightdm-qt/ldmgreeter.cpp b/liblightdm-qt/ldmgreeter.cpp index 9a46b94a..2d14c8be 100644 --- a/liblightdm-qt/ldmgreeter.cpp +++ b/liblightdm-qt/ldmgreeter.cpp @@ -1,7 +1,6 @@ #include "ldmgreeter.h" #include "powermanagementinterface.h" -#include "usermanagerinterface.h" #include "consolekitinterface.h" #include "ldmuser.h" #include "ldmsession.h" @@ -43,7 +42,6 @@ public: int loginDelay; PowerManagementInterface* powerManagement; - UserManagerInterface* userManager; ConsoleKitInterface* consoleKit; int toServerFd; @@ -160,8 +158,6 @@ void LdmGreeter::connectToServer() busType = QDBusConnection::sessionBus(); } - d->userManager = new UserManagerInterface("org.lightdm.LightDisplayManager", "/org/lightdm/LightDisplayManager/Users", busType, this); - char* fd = getenv("LDM_TO_SERVER_FD"); if(!fd) { @@ -390,18 +386,7 @@ int LdmGreeter::timedLoginDelay() const QList<LdmUser> LdmGreeter::users() const { - QDBusPendingReply<QList<LdmUser> > users = d->userManager->GetUsers(); - users.waitForFinished(); - if (users.isValid()) - { - return users.value(); - } - else - { - qDebug() << users.error().name(); - qDebug() << users.error().message(); - return QList<LdmUser>(); - } + // FIXME } QList<LdmSession> LdmGreeter::sessions() const diff --git a/liblightdm-qt/user-manager.xml b/liblightdm-qt/user-manager.xml deleted file mode 100644 index 9857237b..00000000 --- a/liblightdm-qt/user-manager.xml +++ /dev/null @@ -1,21 +0,0 @@ -<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> -<node> - <interface name="org.lightdm.LightDisplayManager.Users"> - - <!-- Method to return the users --> - <method name="GetUsers"> - <!-- name,real name,image,logged in --> - <annotation name="com.trolltech.QtDBus.QtTypeName.Out0" value="QList<LdmUser>"/> - <arg name="users" direction="out" type="a(sssb)"/> - </method> - - <!-- Method to get user default information --> - <method name="GetUserDefaults"> - <arg name="username" direction="in" type="s"/> - <arg name="language" direction="out" type="s"/> - <arg name="layout" direction="out" type="s"/> - <arg name="session" direction="out" type="s"/> - </method> - - </interface> -</node> diff --git a/src/Makefile.am b/src/Makefile.am index 32ddd6bf..74196706 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,8 +25,6 @@ lightdm_SOURCES = \ session.h \ theme.c \ theme.h \ - user-manager.c \ - user-manager.h \ xauth.c \ xauth.h \ xdmcp-protocol.c \ diff --git a/src/greeter-protocol.h b/src/greeter-protocol.h index 3a9c6dd7..bf471f4e 100644 --- a/src/greeter-protocol.h +++ b/src/greeter-protocol.h @@ -20,12 +20,14 @@ typedef enum GREETER_MESSAGE_CONTINUE_AUTHENTICATION = 3, GREETER_MESSAGE_LOGIN = 4, GREETER_MESSAGE_CANCEL_AUTHENTICATION = 5, + GREETER_MESSAGE_GET_USER_DEFAULTS = 6, /* Messages from the server to the greeter */ GREETER_MESSAGE_CONNECTED = 101, GREETER_MESSAGE_QUIT = 102, GREETER_MESSAGE_PROMPT_AUTHENTICATION = 103, - GREETER_MESSAGE_END_AUTHENTICATION = 104 + GREETER_MESSAGE_END_AUTHENTICATION = 104, + GREETER_MESSAGE_USER_DEFAULTS = 106 } GreeterMessage; #endif /* _GREETER_PROTOCOL_H_ */ diff --git a/src/greeter.c b/src/greeter.c index a53e5f1e..cd1338f6 100644 --- a/src/greeter.c +++ b/src/greeter.c @@ -10,6 +10,8 @@ */ #include <string.h> +#include <pwd.h> +#include <errno.h> #include "greeter.h" #include "ldm-marshal.h" @@ -332,6 +334,69 @@ handle_login (Greeter *greeter, gchar *username, gchar *session, gchar *language g_signal_emit (greeter, signals[LOGIN], 0, username, session, language); } +static void +handle_get_user_defaults (Greeter *greeter, gchar *username) +{ + struct passwd *user_info; + GKeyFile *dmrc_file; + gboolean have_dmrc = FALSE; + gchar *language, *layout, *session; + + user_info = getpwnam (username); + if (!user_info) + { + if (errno == 0) + g_warning ("Unable to get information on user %s: User does not exist", username); + else + g_warning ("Unable to get information on user %s: %s", username, strerror (errno)); + } + + dmrc_file = g_key_file_new (); + + /* Load the users login settings (~/.dmrc) */ + if (user_info) + { + gchar *path; + path = g_build_filename (user_info->pw_dir, ".dmrc", NULL); + have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL); + g_free (path); + } + + /* If no .dmrc, then load from the cache */ + if (!have_dmrc) + { + gchar *path, *filename; + + filename = g_strdup_printf ("%s.dmrc", username); + path = g_build_filename (CACHE_DIR, "dmrc", filename, NULL); + g_free (filename); + have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL); + g_free (path); + } + + language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL); + if (!language) + language = g_strdup (""); + layout = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL); + if (!layout) + layout = g_strdup (""); + session = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL); + if (!session) + session = g_strdup (""); + + write_header (greeter, GREETER_MESSAGE_USER_DEFAULTS, string_length (language) + string_length (layout) + string_length (session)); + write_string (greeter, language); + write_string (greeter, layout); + write_string (greeter, session); + flush (greeter); + + g_free (language); + g_free (layout); + g_free (session); + + g_key_file_free (dmrc_file); +} + #define HEADER_SIZE (sizeof (guint32) * 2) static guint32 @@ -451,6 +516,11 @@ got_data_cb (Greeter *greeter) g_free (session_name); g_free (language); break; + case GREETER_MESSAGE_GET_USER_DEFAULTS: + username = read_string (greeter, &offset); + handle_get_user_defaults (greeter, username); + g_free (username); + break; default: g_warning ("Unknown message from greeter: %d", id); break; diff --git a/src/lightdm.c b/src/lightdm.c index 526ec541..de61f6d2 100644 --- a/src/lightdm.c +++ b/src/lightdm.c @@ -18,7 +18,6 @@ #include <unistd.h> #include "display-manager.h" -#include "user-manager.h" #include "xserver.h" static GKeyFile *config_file = NULL; @@ -30,7 +29,6 @@ static GTimer *log_timer; static FILE *log_file; static gboolean debug = FALSE; -static UserManager *user_manager = NULL; static DisplayManager *display_manager = NULL; static GDBusConnection *bus = NULL; @@ -251,98 +249,20 @@ handle_display_manager_call (GDBusConnection *connection, } static GVariant * -user_info_to_args (UserInfo *info) +handle_display_manager_get_property (GDBusConnection *connection, + const gchar *sender, + const gchar *object_path, + const gchar *interface_name, + const gchar *property_name, + GError **error, + gpointer user_data) { - return g_variant_new ("(sssb)", - info->name, - info->real_name ? info->real_name : "", - info->image ? info->image : "", - info->logged_in); -} - -static void -handle_user_manager_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) -{ - if (g_strcmp0 (method_name, "GetUsers") == 0) + if (g_strcmp0 (property_name, "ConfigFile") == 0) { - GVariantBuilder *builder; - GVariant *arg0; - GList *users, *iter; - - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("()"))) - return; - - builder = g_variant_builder_new (G_VARIANT_TYPE ("a(sssb)")); - users = user_manager_get_users (user_manager); - for (iter = users; iter; iter = iter->next) - { - UserInfo *info = iter->data; - g_variant_builder_add_value (builder, user_info_to_args (info)); - } - arg0 = g_variant_builder_end (builder); - g_dbus_method_invocation_return_value (invocation, g_variant_new_tuple (&arg0, 1)); - g_variant_builder_unref (builder); + return g_variant_new_string (config_path); } - else if (g_strcmp0 (method_name, "GetUserDefaults") == 0) - { - gchar *username, *language, *layout, *session; - if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(s)"))) - return; - - g_variant_get (parameters, "(s)", &username); - if (user_manager_get_user_defaults (user_manager, username, &language, &layout, &session)) - { - g_dbus_method_invocation_return_value (invocation, g_variant_new ("(sss)", language, layout, session)); - g_free (language); - g_free (layout); - g_free (session); - } - g_free (username); - } -} - -static void -user_added_cb (UserManager *user_manager, UserInfo *info) -{ - g_dbus_connection_emit_signal (bus, - NULL, - "/org/lightdm/LightDisplayManager/Users", - "org.lightdm.LightDisplayManager.Users", - "UserAdded", - user_info_to_args (info), - NULL); -} - -static void -user_changed_cb (UserManager *user_manager, UserInfo *info) -{ - g_dbus_connection_emit_signal (bus, - NULL, - "/org/lightdm/LightDisplayManager/Users", - "org.lightdm.LightDisplayManager.Users", - "UserChanged", - user_info_to_args (info), - NULL); -} - -static void -user_removed_cb (UserManager *user_manager, UserInfo *info) -{ - g_dbus_connection_emit_signal (bus, - NULL, - "/org/lightdm/LightDisplayManager/Users", - "org.lightdm.LightDisplayManager.Users", - "UserRemoved", - g_variant_new ("(s)", info->name), - NULL); + return NULL; } static void @@ -353,6 +273,7 @@ bus_acquired_cb (GDBusConnection *connection, const gchar *display_manager_interface = "<node>" " <interface name='org.lightdm.LightDisplayManager'>" + " <property name='ConfigFile' type='s' access='read'/>" " <method name='AddDisplay'/>" " <method name='SwitchToUser'>" " <arg name='username' direction='in' type='s'/>" @@ -361,43 +282,10 @@ bus_acquired_cb (GDBusConnection *connection, "</node>"; static const GDBusInterfaceVTable display_manager_vtable = { - handle_display_manager_call - }; - - const gchar *user_manager_interface = - "<node>" - " <interface name='org.lightdm.LightDisplayManager.Users'>" - " <method name='GetUsers'>" - " <arg name='users' direction='out' type='a(sssb)'/>" - " </method>" - " <method name='GetUserDefaults'>" - " <arg name='username' direction='in' type='s'/>" - " <arg name='language' direction='out' type='s'/>" - " <arg name='layout' direction='out' type='s'/>" - " <arg name='session' direction='out' type='s'/>" - " </method>" - " <signal name='UserAdded'>" - " <arg name='username' type='s'/>" - " <arg name='real-name' type='s'/>" - " <arg name='image' type='s'/>" - " <arg name='username' type='b'/>" - " </signal>" - " <signal name='UserChanged'>" - " <arg name='username' type='s'/>" - " <arg name='real-name' type='s'/>" - " <arg name='image' type='s'/>" - " <arg name='username' type='b'/>" - " </signal>" - " <signal name='UserRemoved'>" - " <arg name='username' type='s'/>" - " </signal>" - " </interface>" - "</node>"; - static const GDBusInterfaceVTable user_manager_vtable = - { - handle_user_manager_call + handle_display_manager_call, + handle_display_manager_get_property }; - GDBusNodeInfo *display_manager_info, *user_manager_info; + GDBusNodeInfo *display_manager_info; bus = connection; @@ -409,19 +297,6 @@ bus_acquired_cb (GDBusConnection *connection, &display_manager_vtable, NULL, NULL, NULL); - - user_manager_info = g_dbus_node_info_new_for_xml (user_manager_interface, NULL); - g_assert (user_manager_info != NULL); - g_dbus_connection_register_object (connection, - "/org/lightdm/LightDisplayManager/Users", - user_manager_info->interfaces[0], - &user_manager_vtable, - NULL, NULL, - NULL); - - g_signal_connect (user_manager, "user-added", G_CALLBACK (user_added_cb), NULL); - g_signal_connect (user_manager, "user-changed", G_CALLBACK (user_changed_cb), NULL); - g_signal_connect (user_manager, "user-removed", G_CALLBACK (user_removed_cb), NULL); } static void @@ -500,7 +375,6 @@ main(int argc, char **argv) g_debug ("Loaded configuration from %s", config_path); - user_manager = user_manager_new (config_file); display_manager = display_manager_new (config_file); display_manager_start (display_manager); diff --git a/src/user-manager.c b/src/user-manager.c deleted file mode 100644 index 71e201a5..00000000 --- a/src/user-manager.c +++ /dev/null @@ -1,400 +0,0 @@ -/* - * Copyright (C) 2010 Robert Ancell. - * Author: Robert Ancell <robert.ancell@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#include <string.h> -#include <pwd.h> -#include <errno.h> -#include <gio/gio.h> - -#include "user-manager.h" - -enum { - USER_ADDED, - USER_CHANGED, - USER_REMOVED, - LAST_SIGNAL -}; -static guint signals[LAST_SIGNAL] = { 0 }; - -struct UserManagerPrivate -{ - /* Configuration file */ - GKeyFile *config; - - /* File monitor for password file */ - GFileMonitor *passwd_monitor; - - /* TRUE if have scanned users */ - gboolean have_users; - - /* List of users */ - GList *users; -}; - -G_DEFINE_TYPE (UserManager, user_manager, G_TYPE_OBJECT); - -UserManager * -user_manager_new (GKeyFile *config_file) -{ - UserManager *manager; - - manager = g_object_new (USER_MANAGER_TYPE, NULL); - manager->priv->config = config_file; - - return manager; -} - -static gint -compare_user (gconstpointer a, gconstpointer b) -{ - const UserInfo *user_a = a, *user_b = b; - const gchar *name_a, *name_b; - name_a = user_a->real_name ? user_a->real_name : user_a->name; - name_b = user_b->real_name ? user_b->real_name : user_b->name; - return strcmp (name_a, name_b); -} - -static void -load_users (UserManager *manager) -{ - gchar **hidden_users, **hidden_shells; - gchar *value; - gint minimum_uid; - GList *users = NULL, *old_users, *new_users = NULL, *changed_users = NULL, *link; - - if (g_key_file_has_key (manager->priv->config, "UserManager", "minimum-uid", NULL)) - minimum_uid = g_key_file_get_integer (manager->priv->config, "UserManager", "minimum-uid", NULL); - else - minimum_uid = 500; - - value = g_key_file_get_string (manager->priv->config, "UserManager", "hidden-users", NULL); - if (!value) - value = g_strdup ("nobody nobody4 noaccess"); - hidden_users = g_strsplit (value, " ", -1); - g_free (value); - - value = g_key_file_get_string (manager->priv->config, "UserManager", "hidden-shells", NULL); - if (!value) - value = g_strdup ("/bin/false /usr/sbin/nologin"); - hidden_shells = g_strsplit (value, " ", -1); - g_free (value); - - setpwent (); - - while (TRUE) - { - struct passwd *entry; - UserInfo *user; - char **tokens; - gchar *image_path; - int i; - - errno = 0; - entry = getpwent (); - if (!entry) - break; - - /* Ignore system users */ - if (entry->pw_uid < minimum_uid) - continue; - - /* Ignore users disabled by shell */ - if (entry->pw_shell) - { - for (i = 0; hidden_shells[i] && strcmp (entry->pw_shell, hidden_shells[i]) != 0; i++); - if (hidden_shells[i]) - continue; - } - - /* Ignore certain users */ - for (i = 0; hidden_users[i] && strcmp (entry->pw_name, hidden_users[i]) != 0; i++); - if (hidden_users[i]) - continue; - - user = g_malloc0 (sizeof (UserInfo)); - user->name = g_strdup (entry->pw_name); - - tokens = g_strsplit (entry->pw_gecos, ",", -1); - if (tokens[0] != NULL && tokens[0][0] != '\0') - user->real_name = g_strdup (tokens[0]); - else - user->real_name = NULL; - g_strfreev (tokens); - - user->home_dir = g_strdup (entry->pw_dir); - - image_path = g_build_filename (user->home_dir, ".face", NULL); - if (!g_file_test (image_path, G_FILE_TEST_EXISTS)) - { - g_free (image_path); - image_path = g_build_filename (user->home_dir, ".face.icon", NULL); - if (!g_file_test (image_path, G_FILE_TEST_EXISTS)) - { - g_free (image_path); - image_path = NULL; - } - } - if (image_path) - user->image = g_filename_to_uri (image_path, NULL, NULL); - else - user->image = g_strdup (""); - g_free (image_path); - - /* Update existing users if have them */ - for (link = manager->priv->users; link; link = link->next) - { - UserInfo *info = link->data; - if (strcmp (info->name, user->name) == 0) - { - if (strcmp (info->real_name, user->real_name) != 0 || - strcmp (info->image, user->image) != 0 || - strcmp (info->home_dir, user->home_dir) != 0 || - info->logged_in != user->logged_in) - { - g_free (info->real_name); - g_free (info->image); - g_free (info->home_dir); - info->real_name = user->real_name; - info->image = user->image; - info->home_dir = user->home_dir; - info->logged_in = user->logged_in; - g_free (user); - user = info; - changed_users = g_list_insert_sorted (changed_users, user, compare_user); - } - else - { - g_free (user->real_name); - g_free (user->image); - g_free (user->home_dir); - g_free (user); - user = info; - } - break; - } - } - if (!link) - { - /* Only notify once we have loaded the user list */ - if (manager->priv->have_users) - new_users = g_list_insert_sorted (new_users, user, compare_user); - } - users = g_list_insert_sorted (users, user, compare_user); - } - g_strfreev (hidden_users); - g_strfreev (hidden_shells); - - if (errno != 0) - g_warning ("Failed to read password database: %s", strerror (errno)); - - endpwent (); - - /* Use new user list */ - old_users = manager->priv->users; - manager->priv->users = users; - - /* Notify of changes */ - for (link = new_users; link; link = link->next) - { - UserInfo *info = link->data; - g_debug ("User %s added", info->name); - g_signal_emit (manager, signals[USER_ADDED], 0, info); - } - g_list_free (new_users); - for (link = changed_users; link; link = link->next) - { - UserInfo *info = link->data; - g_debug ("User %s changed", info->name); - g_signal_emit (manager, signals[USER_CHANGED], 0, info); - } - g_list_free (changed_users); - for (link = old_users; link; link = link->next) - { - GList *new_link; - - /* See if this user is in the current list */ - for (new_link = manager->priv->users; new_link; new_link = new_link->next) - { - if (new_link->data == link->data) - break; - } - - if (!new_link) - { - UserInfo *info = link->data; - g_debug ("User %s removed", info->name); - g_signal_emit (manager, signals[USER_REMOVED], 0, info); - g_free (info->name); - g_free (info->real_name); - g_free (info->image); - g_free (info->home_dir); - g_free (info); - } - } - g_list_free (old_users); -} - -static void -passwd_changed_cb (GFileMonitor *monitor, GFile *file, GFile *other_file, GFileMonitorEvent event_type, UserManager *manager) -{ - if (event_type == G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT) - { - g_debug ("%s changed, reloading user list", g_file_get_path (file)); - load_users (manager); - } -} - -static void -update_users (UserManager *manager) -{ - GFile *passwd_file; - GError *error = NULL; - - if (manager->priv->have_users) - return; - - /* User listing is disabled */ - if (g_key_file_has_key (manager->priv->config, "UserManager", "load-users", NULL) && - !g_key_file_get_boolean (manager->priv->config, "UserManager", "load-users", NULL)) - { - manager->priv->have_users = TRUE; - return; - } - - load_users (manager); - - /* Watch for changes to user list */ - passwd_file = g_file_new_for_path ("/etc/passwd"); - manager->priv->passwd_monitor = g_file_monitor (passwd_file, G_FILE_MONITOR_NONE, NULL, &error); - g_object_unref (passwd_file); - if (!manager->priv->passwd_monitor) - g_warning ("Error monitoring /etc/passwd: %s", error->message); - else - g_signal_connect (manager->priv->passwd_monitor, "changed", G_CALLBACK (passwd_changed_cb), manager); - g_clear_error (&error); - - manager->priv->have_users = TRUE; -} - -gint -user_manager_get_num_users (UserManager *manager) -{ - update_users (manager); - return g_list_length (manager->priv->users); -} - -const UserInfo * -user_manager_get_user (UserManager *manager, const gchar *username) -{ - GList *link; - - update_users (manager); - - for (link = manager->priv->users; link; link = link->next) - { - UserInfo *info = link->data; - if (strcmp (info->name, username) == 0) - return info; - } - - return NULL; -} - -GList * -user_manager_get_users (UserManager *manager) -{ - update_users (manager); - return manager->priv->users; -} - -gboolean -user_manager_get_user_defaults (UserManager *manager, gchar *username, gchar **language, gchar **layout, gchar **session) -{ - const UserInfo *info; - GKeyFile *dmrc_file; - gboolean have_dmrc; - gchar *path; - - info = user_manager_get_user (manager, username); - if (!info) - { - g_debug ("Unable to get user defaults, user %s does not exist", username); - return FALSE; - } - - dmrc_file = g_key_file_new (); - g_key_file_set_string (dmrc_file, "Desktop", "Language", ""); - g_key_file_set_string (dmrc_file, "Desktop", "Layout", ""); - g_key_file_set_string (dmrc_file, "Desktop", "Session", ""); - - /* Load the users login settings (~/.dmrc) */ - path = g_build_filename (info->home_dir, ".dmrc", NULL); - have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL); - g_free (path); - - /* If no .dmrc, then load from the cache */ - if (!have_dmrc) - { - gchar *filename; - - filename = g_strdup_printf ("%s.dmrc", username); - path = g_build_filename (CACHE_DIR, "dmrc", filename, NULL); - g_free (filename); - have_dmrc = g_key_file_load_from_file (dmrc_file, path, G_KEY_FILE_NONE, NULL); - g_free (path); - } - - *language = g_key_file_get_string (dmrc_file, "Desktop", "Language", NULL); - *layout = g_key_file_get_string (dmrc_file, "Desktop", "Layout", NULL); - *session = g_key_file_get_string (dmrc_file, "Desktop", "Session", NULL); - - g_key_file_free (dmrc_file); - - return TRUE; -} - - -static void -user_manager_init (UserManager *manager) -{ - manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, USER_MANAGER_TYPE, UserManagerPrivate); -} - -static void -user_manager_class_init (UserManagerClass *klass) -{ - g_type_class_add_private (klass, sizeof (UserManagerPrivate)); - - signals[USER_ADDED] = - g_signal_new ("user-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UserManagerClass, user_added), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[USER_CHANGED] = - g_signal_new ("user-changed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UserManagerClass, user_changed), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); - signals[USER_REMOVED] = - g_signal_new ("user-removed", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UserManagerClass, user_removed), - NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_POINTER); -} diff --git a/src/user-manager.h b/src/user-manager.h deleted file mode 100644 index a7e5a8de..00000000 --- a/src/user-manager.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2010 Robert Ancell. - * Author: Robert Ancell <robert.ancell@canonical.com> - * - * This program is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later - * version. See http://www.gnu.org/copyleft/gpl.html the full text of the - * license. - */ - -#ifndef _USER_MANAGER_H_ -#define _USER_MANAGER_H_ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define USER_MANAGER_TYPE (user_manager_get_type()) -#define USER_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), USER_MANAGER_TYPE, UserManager)); - -typedef struct UserManagerPrivate UserManagerPrivate; - -typedef struct -{ - gchar *name; - gchar *real_name; - gchar *image; - gchar *home_dir; - gboolean logged_in; -} UserInfo; - -typedef struct -{ - GObject parent_instance; - UserManagerPrivate *priv; -} UserManager; - -typedef struct -{ - GObjectClass parent_class; - void (*user_added)(UserManager *manager, UserInfo *user); - void (*user_changed)(UserManager *manager, UserInfo *user); - void (*user_removed)(UserManager *manager, UserInfo *user); -} UserManagerClass; - -GType user_manager_get_type (void); - -UserManager *user_manager_new (GKeyFile *config_file); - -gint user_manager_get_num_users (UserManager *manager); - -const UserInfo *user_manager_get_user (UserManager *manager, const gchar *username); - -GList *user_manager_get_users (UserManager *manager); - -gboolean user_manager_get_user_defaults (UserManager *manager, gchar *username, gchar **language, gchar **layout, gchar **session); - -G_END_DECLS - -#endif /* _USER_MANAGER_H_ */ |