# ## Description: add some description ## Origin/Author: add some origin or author ## Bug: bug URL # Description: Add org.gnome.DisplayManager.UserManager interface to gdmserver to be shared between greeter, configuration applet and FUSA applet # Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gdm/+bug/423450 # Upstream: https://bugzilla.gnome.org/show_bug.cgi?id=593996 # From 35aa54f6fe3ff8fa8d6129f805ea243a6204aa65 Mon Sep 17 00:00:00 2001 From: Robert Ancell Date: Fri, 11 Sep 2009 16:01:30 +1000 Subject: [PATCH] Add org.gnome.DisplayManager.UserManager interface to gdmserver diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/configure.ac gdm-2.30.2.new/configure.ac --- gdm-2.30.2/configure.ac 2010-06-09 14:09:07.617036046 +1000 +++ gdm-2.30.2.new/configure.ac 2010-06-09 14:09:08.137025806 +1000 @@ -64,6 +64,7 @@ polkit-gobject-1 >= $POLKIT_GOBJECT_REQUIRED_VERSION gobject-2.0 >= $GLIB_REQUIRED_VERSION gio-2.0 >= $GLIB_REQUIRED_VERSION + gconf-2.0 >= $GCONF_REQUIRED_VERSION ) AC_SUBST(COMMON_CFLAGS) AC_SUBST(COMMON_LIBS) @@ -979,6 +980,17 @@ fi AC_SUBST(logdir, $GDM_LOG_DIR) +AC_ARG_WITH(cache-dir, + AS_HELP_STRING([--with-cache-dir=], + [cache dir])) + +if ! test -z "$with_cache_dir"; then + GDM_CACHE_DIR=$with_cache_dir +else + GDM_CACHE_DIR=/var/cache/gdm +fi +AC_SUBST(cachedir, $GDM_CACHE_DIR) + withval="" AC_ARG_WITH(at-bindir, AS_HELP_STRING([--with-at-bindir=] diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/gdm-user.c gdm-2.30.2.new/daemon/gdm-user.c --- gdm-2.30.2/daemon/gdm-user.c 1970-01-01 10:00:00.000000000 +1000 +++ gdm-2.30.2.new/daemon/gdm-user.c 2010-06-09 14:09:08.137025806 +1000 @@ -0,0 +1,747 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2004-2005 James M. Cape . + * Copyright (C) 2007-2008 William Jon McCann + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "gdm-user-manager.h" +#include "gdm-user-private.h" + +#define GDM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_USER, GdmUserClass)) +#define GDM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_USER)) +#define GDM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), GDM_TYPE_USER, GdmUserClass)) + +#define GLOBAL_FACEDIR DATADIR "/faces" +#define MAX_ICON_SIZE 128 +#define MAX_FILE_SIZE 65536 +#define MINIMAL_UID 100 + +enum { + PROP_0, + PROP_MANAGER, + PROP_REAL_NAME, + PROP_DISPLAY_NAME, + PROP_USER_NAME, + PROP_UID, + PROP_HOME_DIR, + PROP_SHELL, + PROP_ICON_URL, + PROP_LOGIN_FREQUENCY, +}; + +enum { + ICON_CHANGED, + SESSIONS_CHANGED, + LAST_SIGNAL +}; + +struct _GdmUser { + GObject parent; + + GdmUserManager *manager; + + uid_t uid; + char *user_name; + char *real_name; + char *display_name; + char *home_dir; + char *shell; + char *icon_url; + GList *sessions; + gulong login_frequency; + + GFileMonitor *icon_monitor; +}; + +typedef struct _GdmUserClass +{ + GObjectClass parent_class; + + void (* icon_changed) (GdmUser *user); + void (* sessions_changed) (GdmUser *user); +} GdmUserClass; + +static void gdm_user_finalize (GObject *object); + +static guint signals[LAST_SIGNAL] = { 0 }; + +G_DEFINE_TYPE (GdmUser, gdm_user, G_TYPE_OBJECT) + +static int +session_compare (const char *a, + const char *b) +{ + if (a == NULL) { + return 1; + } else if (b == NULL) { + return -1; + } + + return strcmp (a, b); +} + +void +_gdm_user_add_session (GdmUser *user, + const char *ssid) +{ + GList *li; + + g_return_if_fail (GDM_IS_USER (user)); + g_return_if_fail (ssid != NULL); + + li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare); + if (li == NULL) { + g_debug ("GdmUser: adding session %s", ssid); + user->sessions = g_list_prepend (user->sessions, g_strdup (ssid)); + g_signal_emit (user, signals[SESSIONS_CHANGED], 0); + } else { + g_debug ("GdmUser: session already present: %s", ssid); + } +} + +void +_gdm_user_remove_session (GdmUser *user, + const char *ssid) +{ + GList *li; + + g_return_if_fail (GDM_IS_USER (user)); + g_return_if_fail (ssid != NULL); + + li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare); + if (li != NULL) { + g_debug ("GdmUser: removing session %s", ssid); + g_free (li->data); + user->sessions = g_list_delete_link (user->sessions, li); + g_signal_emit (user, signals[SESSIONS_CHANGED], 0); + } else { + g_debug ("GdmUser: session not found: %s", ssid); + } +} + +guint +gdm_user_get_num_sessions (GdmUser *user) +{ + return g_list_length (user->sessions); +} + +GList * +gdm_user_get_sessions (GdmUser *user) +{ + return user->sessions; +} + +static void +_gdm_user_set_login_frequency (GdmUser *user, + gulong login_frequency) +{ + user->login_frequency = login_frequency; + g_object_notify (G_OBJECT (user), "login-frequency"); +} + +static void +gdm_user_set_property (GObject *object, + guint param_id, + const GValue *value, + GParamSpec *pspec) +{ + GdmUser *user; + + user = GDM_USER (object); + + switch (param_id) { + case PROP_MANAGER: + user->manager = g_value_get_object (value); + g_assert (user->manager); + break; + case PROP_LOGIN_FREQUENCY: + _gdm_user_set_login_frequency (user, g_value_get_ulong (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gdm_user_get_property (GObject *object, + guint param_id, + GValue *value, + GParamSpec *pspec) +{ + GdmUser *user; + + user = GDM_USER (object); + + switch (param_id) { + case PROP_MANAGER: + g_value_set_object (value, user->manager); + break; + case PROP_USER_NAME: + g_value_set_string (value, user->user_name); + break; + case PROP_REAL_NAME: + g_value_set_string (value, user->real_name); + break; + case PROP_DISPLAY_NAME: + g_value_set_string (value, user->display_name); + break; + case PROP_HOME_DIR: + g_value_set_string (value, user->home_dir); + break; + case PROP_UID: + g_value_set_ulong (value, user->uid); + break; + case PROP_SHELL: + g_value_set_string (value, user->shell); + break; + case PROP_ICON_URL: + g_value_set_string (value, user->icon_url); + break; + case PROP_LOGIN_FREQUENCY: + g_value_set_ulong (value, user->login_frequency); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); + break; + } +} + +static void +gdm_user_class_init (GdmUserClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->set_property = gdm_user_set_property; + gobject_class->get_property = gdm_user_get_property; + gobject_class->finalize = gdm_user_finalize; + + g_object_class_install_property (gobject_class, + PROP_MANAGER, + g_param_spec_object ("manager", + _("Manager"), + _("The user manager object this user is controlled by."), + GDM_TYPE_USER_MANAGER, + (G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY))); + + g_object_class_install_property (gobject_class, + PROP_REAL_NAME, + g_param_spec_string ("real-name", + "Real Name", + "The real name to display for this user.", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_DISPLAY_NAME, + g_param_spec_string ("display-name", + "Display Name", + "The unique name to display for this user.", + NULL, + G_PARAM_READABLE)); + + g_object_class_install_property (gobject_class, + PROP_UID, + g_param_spec_ulong ("uid", + "User ID", + "The UID for this user.", + 0, G_MAXULONG, 0, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, + PROP_USER_NAME, + g_param_spec_string ("user-name", + "User Name", + "The login name for this user.", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, + PROP_HOME_DIR, + g_param_spec_string ("home-directory", + "Home Directory", + "The home directory for this user.", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, + PROP_SHELL, + g_param_spec_string ("shell", + "Shell", + "The shell for this user.", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, + PROP_SHELL, + g_param_spec_string ("icon-url", + "Icon URL", + "The icon for this user.", + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (gobject_class, + PROP_LOGIN_FREQUENCY, + g_param_spec_ulong ("login-frequency", + "login frequency", + "login frequency", + 0, + G_MAXULONG, + 0, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT)); + + signals [ICON_CHANGED] = + g_signal_new ("icon-changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserClass, icon_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [SESSIONS_CHANGED] = + g_signal_new ("sessions-changed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserClass, sessions_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + + +static void +on_icon_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + GdmUser *user) +{ + g_debug ("Icon changed: %d", event_type); + + if (event_type != G_FILE_MONITOR_EVENT_CHANGED && + event_type != G_FILE_MONITOR_EVENT_CREATED) { + return; + } + + _gdm_user_icon_changed (user); +} + +static void +update_icon_monitor (GdmUser *user) +{ + GFile *file; + GError *error; + char *path; + + if (user->home_dir == NULL) { + return; + } + + if (user->icon_monitor != NULL) { + g_file_monitor_cancel (user->icon_monitor); + user->icon_monitor = NULL; + } + + path = g_build_filename (user->home_dir, ".face", NULL); + g_debug ("adding monitor for '%s'", path); + file = g_file_new_for_path (path); + error = NULL; + user->icon_monitor = g_file_monitor_file (file, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (user->icon_monitor != NULL) { + g_signal_connect (user->icon_monitor, + "changed", + G_CALLBACK (on_icon_monitor_changed), + user); + } else { + g_warning ("Unable to monitor %s: %s", path, error->message); + g_error_free (error); + } + g_object_unref (file); + + g_free (user->icon_url); + user->icon_url = g_strjoin(NULL, "file://", path, NULL); + g_object_notify (G_OBJECT (user), "icon-url"); + + g_free (path); +} + +static void +gdm_user_init (GdmUser *user) +{ + user->manager = NULL; + user->user_name = NULL; + user->real_name = NULL; + user->display_name = NULL; + user->sessions = NULL; + user->icon_url = NULL; +} + +static void +gdm_user_finalize (GObject *object) +{ + GdmUser *user; + + user = GDM_USER (object); + + g_file_monitor_cancel (user->icon_monitor); + + g_free (user->user_name); + g_free (user->real_name); + g_free (user->display_name); + g_free (user->icon_url); + + if (G_OBJECT_CLASS (gdm_user_parent_class)->finalize) + (*G_OBJECT_CLASS (gdm_user_parent_class)->finalize) (object); +} + +/** + * _gdm_user_update: + * @user: the user object to update. + * @pwent: the user data to use. + * + * Updates the properties of @user using the data in @pwent. + * + * Since: 1.0 + **/ +void +_gdm_user_update (GdmUser *user, + const struct passwd *pwent) +{ + gchar *real_name = NULL; + + g_return_if_fail (GDM_IS_USER (user)); + g_return_if_fail (pwent != NULL); + + g_object_freeze_notify (G_OBJECT (user)); + + /* Display Name */ + 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, + (first_comma - valid_utf8_name)); + } else if (valid_utf8_name) { + real_name = g_strdup (valid_utf8_name); + } else { + real_name = NULL; + } + + if (real_name && real_name[0] == '\0') { + g_free (real_name); + real_name = NULL; + } + } else { + real_name = NULL; + } + + if ((real_name && !user->real_name) || + (!real_name && user->real_name) || + (real_name && + user->real_name && + strcmp (real_name, user->real_name) != 0)) { + g_free (user->real_name); + user->real_name = real_name; + g_object_notify (G_OBJECT (user), "real-name"); + } else { + g_free (real_name); + } + + /* Unique Display Name */ + if ((!user->real_name && user->display_name) || + (user->real_name && + user->display_name && + strncmp (user->real_name, user->display_name, strlen (user->real_name)) != 0)) { + g_free (user->display_name); + user->display_name = NULL; + g_object_notify (G_OBJECT (user), "display-name"); + } + + /* UID */ + if (pwent->pw_uid != user->uid) { + user->uid = pwent->pw_uid; + g_object_notify (G_OBJECT (user), "uid"); + } + + /* Username */ + if ((pwent->pw_name && !user->user_name) || + (!pwent->pw_name && user->user_name) || + (pwent->pw_name && + user->user_name && + strcmp (user->user_name, pwent->pw_name) != 0)) { + g_free (user->user_name); + user->user_name = g_strdup (pwent->pw_name); + g_object_notify (G_OBJECT (user), "user-name"); + } + + /* Home Directory */ + if ((pwent->pw_dir && !user->home_dir) || + (!pwent->pw_dir && user->home_dir) || + strcmp (user->home_dir, pwent->pw_dir) != 0) { + g_free (user->home_dir); + user->home_dir = g_strdup (pwent->pw_dir); + g_object_notify (G_OBJECT (user), "home-directory"); + g_signal_emit (user, signals[ICON_CHANGED], 0); + } + + /* Shell */ + if ((pwent->pw_shell && !user->shell) || + (!pwent->pw_shell && user->shell) || + (pwent->pw_shell && + user->shell && + strcmp (user->shell, pwent->pw_shell) != 0)) { + g_free (user->shell); + user->shell = g_strdup (pwent->pw_shell); + g_object_notify (G_OBJECT (user), "shell"); + } + + update_icon_monitor (user); + + g_object_thaw_notify (G_OBJECT (user)); +} + +/** + * _gdm_user_icon_changed: + * @user: the user to emit the signal for. + * + * Emits the "icon-changed" signal for @user. + * + * Since: 1.0 + **/ +void +_gdm_user_icon_changed (GdmUser *user) +{ + g_return_if_fail (GDM_IS_USER (user)); + + g_signal_emit (user, signals[ICON_CHANGED], 0); +} + +/** + * gdm_user_get_uid: + * @user: the user object to examine. + * + * Retrieves the ID of @user. + * + * Returns: a pointer to an array of characters which must not be modified or + * freed, or %NULL. + * + * Since: 1.0 + **/ + +uid_t +gdm_user_get_uid (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), -1); + + return user->uid; +} + +/** + * gdm_user_get_real_name: + * @user: the user object to examine. + * + * Retrieves the display name of @user. + * + * Returns: a pointer to an array of characters which must not be modified or + * freed, or %NULL. + * + * Since: 1.0 + **/ +G_CONST_RETURN gchar * +gdm_user_get_real_name (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), NULL); + + return (user->real_name ? user->real_name : user->user_name); +} + +/** + * gdm_user_get_display_name: + * @user: the user object to examine. + * + * Retrieves the unique display name of @user. + * + * Returns: a pointer to an array of characters which must not be modified or + * freed, or %NULL. + * + * Since: 1.0 + **/ +G_CONST_RETURN gchar * +gdm_user_get_display_name (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), NULL); + + return (user->display_name ? user->display_name + : gdm_user_get_real_name (user)); +} + +/** + * gdm_user_get_user_name: + * @user: the user object to examine. + * + * Retrieves the login name of @user. + * + * Returns: a pointer to an array of characters which must not be modified or + * freed, or %NULL. + * + * Since: 1.0 + **/ + +G_CONST_RETURN gchar * +gdm_user_get_user_name (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), NULL); + + return user->user_name; +} + +/** + * gdm_user_get_home_directory: + * @user: the user object to examine. + * + * Retrieves the home directory of @user. + * + * Returns: a pointer to an array of characters which must not be modified or + * freed, or %NULL. + * + * Since: 1.0 + **/ + +G_CONST_RETURN gchar * +gdm_user_get_home_directory (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), NULL); + + return user->home_dir; +} + +/** + * gdm_user_get_shell: + * @user: the user object to examine. + * + * Retrieves the login shell of @user. + * + * Returns: a pointer to an array of characters which must not be modified or + * freed, or %NULL. + * + * Since: 1.0 + **/ + +G_CONST_RETURN gchar * +gdm_user_get_shell (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), NULL); + + return user->shell; +} + +gulong +gdm_user_get_login_frequency (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), 0); + + return user->login_frequency; +} + +int +gdm_user_collate (GdmUser *user1, + GdmUser *user2) +{ + const char *str1; + const char *str2; + gulong num1; + gulong num2; + + g_return_val_if_fail (GDM_IS_USER (user1), 0); + g_return_val_if_fail (GDM_IS_USER (user2), 0); + + if (user1->real_name != NULL) { + str1 = user1->real_name; + } else { + str1 = user1->user_name; + } + + if (user2->real_name != NULL) { + str2 = user2->real_name; + } else { + str2 = user2->user_name; + } + + num1 = user1->login_frequency; + num2 = user2->login_frequency; + g_debug ("Login freq 1=%u 2=%u", (guint)num1, (guint)num2); + if (num1 > num2) { + return -1; + } + + if (num1 < num2) { + return 1; + } + + /* if login frequency is equal try names */ + if (str1 == NULL && str2 != NULL) { + return -1; + } + + if (str1 != NULL && str2 == NULL) { + return 1; + } + + if (str1 == NULL && str2 == NULL) { + return 0; + } + + return g_utf8_collate (str1, str2); +} + +G_CONST_RETURN char * +gdm_user_get_icon_url (GdmUser *user) +{ + g_return_val_if_fail (GDM_IS_USER (user), NULL); + + /* FIXME: Icon can be one of: + * ~/.face + * ~/.face.icon + * ~/.gnome/gdm:[face]picture + * ${GlobalFaceDir}/${username} + * ${GlobalFaceDir}/${username}.png + * but we only monitor the first. + */ + return user->icon_url; +} diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/gdm-user.h gdm-2.30.2.new/daemon/gdm-user.h --- gdm-2.30.2/daemon/gdm-user.h 1970-01-01 10:00:00.000000000 +1000 +++ gdm-2.30.2.new/daemon/gdm-user.h 2010-06-09 14:09:08.137025806 +1000 @@ -0,0 +1,57 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2004-2005 James M. Cape . + * Copyright (C) 2007-2008 William Jon McCann + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Facade object for user data, owned by GdmUserManager + */ + +#ifndef __GDM_USER__ +#define __GDM_USER__ 1 + +#include +#include + +G_BEGIN_DECLS + +#define GDM_TYPE_USER (gdm_user_get_type ()) +#define GDM_USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDM_TYPE_USER, GdmUser)) +#define GDM_IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDM_TYPE_USER)) + +typedef struct _GdmUser GdmUser; + +GType gdm_user_get_type (void) G_GNUC_CONST; + +uid_t gdm_user_get_uid (GdmUser *user); +G_CONST_RETURN char *gdm_user_get_user_name (GdmUser *user); +G_CONST_RETURN char *gdm_user_get_real_name (GdmUser *user); +G_CONST_RETURN char *gdm_user_get_display_name (GdmUser *user); +G_CONST_RETURN char *gdm_user_get_home_directory (GdmUser *user); +G_CONST_RETURN char *gdm_user_get_shell (GdmUser *user); +guint gdm_user_get_num_sessions (GdmUser *user); +GList *gdm_user_get_sessions (GdmUser *user); +gulong gdm_user_get_login_frequency (GdmUser *user); +G_CONST_RETURN char *gdm_user_get_icon_url (GdmUser *user); + +gint gdm_user_collate (GdmUser *user1, + GdmUser *user2); + +G_END_DECLS + +#endif diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/gdm-user-manager.c gdm-2.30.2.new/daemon/gdm-user-manager.c --- gdm-2.30.2/daemon/gdm-user-manager.c 1970-01-01 10:00:00.000000000 +1000 +++ gdm-2.30.2.new/daemon/gdm-user-manager.c 2010-06-09 14:09:31.967221528 +1000 @@ -0,0 +1,1730 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007-2008 William Jon McCann + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PATHS_H +#include +#endif /* HAVE_PATHS_H */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "gdm-user-manager.h" +#include "gdm-user-manager-glue.h" +#include "gdm-user-private.h" +#include "gdm-settings-keys.h" + +#define GDM_USER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerPrivate)) + +#define GDM_DBUS_PATH "/org/gnome/DisplayManager" +#define GDM_USER_MANAGER_DBUS_PATH GDM_DBUS_PATH "/UserManager" +#define GDM_USER_MANAGER_DBUS_NAME "org.gnome.DisplayManager.UserManager" + +#define CK_NAME "org.freedesktop.ConsoleKit" +#define CK_PATH "/org/freedesktop/ConsoleKit" +#define CK_INTERFACE "org.freedesktop.ConsoleKit" + +#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" +#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" +#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" +#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" + +/* Prefs Defaults */ +#define DEFAULT_ALLOW_ROOT TRUE +#define DEFAULT_MAX_ICON_SIZE 128 +#define DEFAULT_USER_MAX_FILE 65536 + +#ifdef __sun +#define DEFAULT_MINIMAL_UID 100 +#else +#define DEFAULT_MINIMAL_UID 500 +#endif + +#ifndef _PATH_SHELLS +#define _PATH_SHELLS "/etc/shells" +#endif +#define PATH_PASSWD "/etc/passwd" + +#define DEFAULT_GLOBAL_FACE_DIR DATADIR "/faces" +#define DEFAULT_USER_ICON "stock_person" + +#define LOGIN_CACHE_FILE CACHEDIR "/login_frequency.cache" + +struct GdmUserManagerPrivate +{ + GHashTable *users; + GHashTable *sessions; + GHashTable *shells; + DBusGConnection *connection; + DBusGProxy *seat_proxy; + char *seat_id; + + GFileMonitor *passwd_monitor; + GFileMonitor *shells_monitor; + + GSList *exclude; + GSList *include; + gboolean include_all; + + guint reload_id; + guint ck_history_id; + + guint8 loaded_passwd : 1; + guint8 users_dirty : 1; + guint8 loaded_cache : 1; + guint8 loading_users : 1; +}; + +enum { + LOADING_USERS, + USERS_LOADED, + USER_ADDED, + USER_REMOVED, + USER_UPDATED, + LAST_SIGNAL +}; + +static guint signals [LAST_SIGNAL] = { 0, }; + +static void gdm_user_manager_class_init (GdmUserManagerClass *klass); +static void gdm_user_manager_init (GdmUserManager *user_manager); +static void gdm_user_manager_finalize (GObject *object); + +static gpointer user_manager_object = NULL; + +G_DEFINE_TYPE (GdmUserManager, gdm_user_manager, G_TYPE_OBJECT) + +GQuark +gdm_user_manager_error_quark (void) +{ + static GQuark ret = 0; + if (ret == 0) { + ret = g_quark_from_static_string ("gdm_user_manager_error"); + } + + return ret; +} + +static void +on_user_sessions_changed (GdmUser *user, + GdmUserManager *manager) +{ + guint nsessions; + + nsessions = gdm_user_get_num_sessions (user); + + g_debug ("GdmUserManager: sessions changed user=%s num=%d", + gdm_user_get_user_name (user), + nsessions); + + /* only signal on zero and one */ + if (nsessions > 1) { + return; + } + + g_signal_emit (manager, signals [USER_UPDATED], 0, gdm_user_get_uid (user)); +} + +static void +on_user_icon_changed (GdmUser *user, + GdmUserManager *manager) +{ + g_debug ("GdmUserManager: user icon changed"); +} + +static char * +get_seat_id_for_session (DBusGConnection *connection, + const char *session_id) +{ + DBusGProxy *proxy; + GError *error; + char *seat_id; + gboolean res; + + proxy = NULL; + seat_id = NULL; + + proxy = dbus_g_proxy_new_for_name (connection, + CK_NAME, + session_id, + CK_SESSION_INTERFACE); + if (proxy == NULL) { + g_warning ("Failed to connect to the ConsoleKit session object"); + goto out; + } + + error = NULL; + res = dbus_g_proxy_call (proxy, + "GetSeatId", + &error, + G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, &seat_id, + G_TYPE_INVALID); + if (! res) { + if (error != NULL) { + g_debug ("Failed to identify the current seat: %s", error->message); + g_error_free (error); + } else { + g_debug ("Failed to identify the current seat"); + } + } + out: + if (proxy != NULL) { + g_object_unref (proxy); + } + + return seat_id; +} + +static char * +get_x11_display_for_session (DBusGConnection *connection, + const char *session_id) +{ + DBusGProxy *proxy; + GError *error; + char *x11_display; + gboolean res; + + proxy = NULL; + x11_display = NULL; + + proxy = dbus_g_proxy_new_for_name (connection, + CK_NAME, + session_id, + CK_SESSION_INTERFACE); + if (proxy == NULL) { + g_warning ("Failed to connect to the ConsoleKit session object"); + goto out; + } + + error = NULL; + res = dbus_g_proxy_call (proxy, + "GetX11Display", + &error, + G_TYPE_INVALID, + G_TYPE_STRING, &x11_display, + G_TYPE_INVALID); + if (! res) { + if (error != NULL) { + g_debug ("Failed to identify the x11 display: %s", error->message); + g_error_free (error); + } else { + g_debug ("Failed to identify the x11 display"); + } + } + out: + if (proxy != NULL) { + g_object_unref (proxy); + } + + return x11_display; +} + +static gint +match_name_cmpfunc (gconstpointer a, + gconstpointer b) +{ + if (a == NULL || b == NULL) { + return -1; + } + + return g_strcmp0 ((char *) a, + (char *) b); +} + +static gboolean +user_in_exclude_list (GdmUserManager *manager, + const char *user) +{ + GSList *found; + gboolean ret = FALSE; + + g_debug ("checking exclude list"); + + /* always exclude the "gdm" user. */ + if (user == NULL || (strcmp (user, GDM_USERNAME) == 0)) { + return TRUE; + } + + if (manager->priv->exclude != NULL) { + found = g_slist_find_custom (manager->priv->exclude, + user, + match_name_cmpfunc); + if (found != NULL) { + ret = TRUE; + } + } + return ret; +} + +static gboolean +maybe_add_session_for_user (GdmUserManager *manager, + GdmUser *user, + const char *ssid) +{ + char *sid; + char *x11_display; + gboolean ret; + + ret = FALSE; + sid = NULL; + x11_display = NULL; + + /* skip if on another seat */ + sid = get_seat_id_for_session (manager->priv->connection, ssid); + if (sid == NULL + || manager->priv->seat_id == NULL + || strcmp (sid, manager->priv->seat_id) != 0) { + g_debug ("GdmUserManager: not adding session on other seat: %s", ssid); + goto out; + } + + /* skip if doesn't have an x11 display */ + x11_display = get_x11_display_for_session (manager->priv->connection, ssid); + if (x11_display == NULL || x11_display[0] == '\0') { + g_debug ("GdmUserManager: not adding session without a x11 display: %s", ssid); + goto out; + } + + if (user_in_exclude_list (manager, gdm_user_get_user_name (user))) { + g_debug ("GdmUserManager: excluding user '%s'", gdm_user_get_user_name (user)); + goto out; + } + + g_hash_table_insert (manager->priv->sessions, + g_strdup (ssid), + g_strdup (gdm_user_get_user_name (user))); + + _gdm_user_add_session (user, ssid); + g_debug ("GdmUserManager: added session for user: %s", gdm_user_get_user_name (user)); + + ret = TRUE; + + out: + g_free (sid); + g_free (x11_display); + + return ret; +} + +static void +add_sessions_for_user (GdmUserManager *manager, + GdmUser *user) +{ + DBusGProxy *proxy; + GError *error; + gboolean res; + guint32 uid; + GPtrArray *sessions; + int i; + + proxy = dbus_g_proxy_new_for_name (manager->priv->connection, + CK_NAME, + CK_MANAGER_PATH, + CK_MANAGER_INTERFACE); + if (proxy == NULL) { + g_warning ("Failed to connect to the ConsoleKit manager object"); + goto out; + } + + uid = gdm_user_get_uid (user); + + g_debug ("Getting list of sessions for user %u", uid); + + error = NULL; + res = dbus_g_proxy_call (proxy, + "GetSessionsForUnixUser", + &error, + G_TYPE_UINT, uid, + G_TYPE_INVALID, + dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), + &sessions, + G_TYPE_INVALID); + if (! res) { + if (error != NULL) { + g_debug ("Failed to find sessions for user: %s", error->message); + g_error_free (error); + } else { + g_debug ("Failed to find sessions for user"); + } + goto out; + } + + g_debug ("Found %d sessions for user %s", sessions->len, gdm_user_get_user_name (user)); + + for (i = 0; i < sessions->len; i++) { + char *ssid; + + ssid = g_ptr_array_index (sessions, i); + maybe_add_session_for_user (manager, user, ssid); + } + + g_ptr_array_foreach (sessions, (GFunc)g_free, NULL); + g_ptr_array_free (sessions, TRUE); + + out: + if (proxy != NULL) { + g_object_unref (proxy); + } +} + +static GdmUser * +create_user (GdmUserManager *manager) +{ + GdmUser *user; + + user = g_object_new (GDM_TYPE_USER, "manager", manager, NULL); + g_signal_connect (user, + "sessions-changed", + G_CALLBACK (on_user_sessions_changed), + manager); + g_signal_connect (user, + "icon-changed", + G_CALLBACK (on_user_icon_changed), + manager); + return user; +} + +static gint +match_real_name_cmpfunc (gconstpointer a, + gconstpointer b) +{ + if (a == b) + return -1; + + return g_strcmp0 (gdm_user_get_real_name ((GdmUser *) a), + gdm_user_get_real_name ((GdmUser *) b)); +} + +static gboolean +match_real_name_hrfunc (gpointer key, + gpointer value, + gpointer user_data) +{ + return (g_strcmp0 (user_data, gdm_user_get_real_name (value)) == 0); +} + +static void +add_user (GdmUserManager *manager, + GdmUser *user) +{ + GdmUser *dup; + + add_sessions_for_user (manager, user); + dup = g_hash_table_find (manager->priv->users, + match_real_name_hrfunc, + (char *) gdm_user_get_real_name (user)); + if (dup != NULL) { + //_gdm_user_show_full_display_name (user); + //_gdm_user_show_full_display_name (dup); + } + g_hash_table_insert (manager->priv->users, + g_strdup (gdm_user_get_user_name (user)), + g_object_ref (user)); + + g_signal_emit (manager, signals[USER_ADDED], 0, gdm_user_get_uid (user)); +} + +static GdmUser * +add_new_user_for_pwent (GdmUserManager *manager, + struct passwd *pwent) +{ + GdmUser *user; + + g_debug ("Creating new user"); + + user = create_user (manager); + _gdm_user_update (user, pwent); + + add_user (manager, user); + + return user; +} + +static char * +get_current_seat_id (DBusGConnection *connection) +{ + DBusGProxy *proxy; + GError *error; + char *session_id; + char *seat_id; + gboolean res; + + proxy = NULL; + session_id = NULL; + seat_id = NULL; + + proxy = dbus_g_proxy_new_for_name (connection, + CK_NAME, + CK_MANAGER_PATH, + CK_MANAGER_INTERFACE); + if (proxy == NULL) { + g_warning ("Failed to connect to the ConsoleKit manager object"); + goto out; + } + + error = NULL; + res = dbus_g_proxy_call (proxy, + "GetCurrentSession", + &error, + G_TYPE_INVALID, + DBUS_TYPE_G_OBJECT_PATH, + &session_id, + G_TYPE_INVALID); + if (! res) { + if (error != NULL) { + g_debug ("Failed to identify the current session: %s", error->message); + g_error_free (error); + } else { + g_debug ("Failed to identify the current session"); + } + goto out; + } + + seat_id = get_seat_id_for_session (connection, session_id); + + out: + if (proxy != NULL) { + g_object_unref (proxy); + } + g_free (session_id); + + return seat_id; +} + +static gboolean +get_uid_from_session_id (GdmUserManager *manager, + const char *session_id, + uid_t *uidp) +{ + DBusGProxy *proxy; + GError *error; + guint uid; + gboolean res; + + proxy = dbus_g_proxy_new_for_name (manager->priv->connection, + CK_NAME, + session_id, + CK_SESSION_INTERFACE); + if (proxy == NULL) { + g_warning ("Failed to connect to the ConsoleKit session object"); + return FALSE; + } + + error = NULL; + res = dbus_g_proxy_call (proxy, + "GetUnixUser", + &error, + G_TYPE_INVALID, + G_TYPE_UINT, &uid, + G_TYPE_INVALID); + g_object_unref (proxy); + + if (! res) { + if (error != NULL) { + g_warning ("Failed to query the session: %s", error->message); + g_error_free (error); + } else { + g_warning ("Failed to query the session"); + } + return FALSE; + } + + if (uidp != NULL) { + *uidp = (uid_t) uid; + } + + return TRUE; +} + +static void +seat_session_added (DBusGProxy *seat_proxy, + const char *session_id, + GdmUserManager *manager) +{ + uid_t uid; + gboolean res; + struct passwd *pwent; + GdmUser *user; + gboolean is_new; + + g_debug ("Session added: %s", session_id); + + res = get_uid_from_session_id (manager, session_id, &uid); + if (! res) { + g_warning ("Unable to lookup user for session"); + return; + } + + errno = 0; + pwent = getpwuid (uid); + if (pwent == NULL) { + g_warning ("Unable to lookup user ID %d: %s", (int)uid, g_strerror (errno)); + return; + } + + /* check exclusions up front */ + if (user_in_exclude_list (manager, pwent->pw_name)) { + g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name); + return; + } + + user = g_hash_table_lookup (manager->priv->users, pwent->pw_name); + if (user == NULL) { + g_debug ("Creating new user"); + + user = create_user (manager); + _gdm_user_update (user, pwent); + is_new = TRUE; + } else { + is_new = FALSE; + } + + res = maybe_add_session_for_user (manager, user, session_id); + + /* only add the user if we added a session */ + if (is_new) { + if (res) { + add_user (manager, user); + } else { + g_object_unref (user); + } + } +} + +static void +seat_session_removed (DBusGProxy *seat_proxy, + const char *session_id, + GdmUserManager *manager) +{ + GdmUser *user; + char *username; + + g_debug ("Session removed: %s", session_id); + + /* since the session object may already be gone + * we can't query CK directly */ + + username = g_hash_table_lookup (manager->priv->sessions, session_id); + if (username == NULL) { + return; + } + + user = g_hash_table_lookup (manager->priv->users, username); + if (user == NULL) { + /* nothing to do */ + return; + } + + g_debug ("GdmUserManager: Session removed for %s", username); + _gdm_user_remove_session (user, session_id); +} + +static void +on_proxy_destroy (DBusGProxy *proxy, + GdmUserManager *manager) +{ + g_debug ("GdmUserManager: seat proxy destroyed"); + + manager->priv->seat_proxy = NULL; +} + +static void +get_seat_proxy (GdmUserManager *manager) +{ + DBusGProxy *proxy; + GError *error; + + g_assert (manager->priv->seat_proxy == NULL); + + error = NULL; + manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); + if (manager->priv->connection == NULL) { + if (error != NULL) { + g_warning ("Failed to connect to the D-Bus daemon: %s", error->message); + g_error_free (error); + } else { + g_warning ("Failed to connect to the D-Bus daemon"); + } + return; + } + + manager->priv->seat_id = get_current_seat_id (manager->priv->connection); + if (manager->priv->seat_id == NULL) { + return; + } + + g_debug ("GdmUserManager: Found current seat: %s", manager->priv->seat_id); + + error = NULL; + proxy = dbus_g_proxy_new_for_name_owner (manager->priv->connection, + CK_NAME, + manager->priv->seat_id, + CK_SEAT_INTERFACE, + &error); + + if (proxy == NULL) { + if (error != NULL) { + g_warning ("Failed to connect to the ConsoleKit seat object: %s", + error->message); + g_error_free (error); + } else { + g_warning ("Failed to connect to the ConsoleKit seat object"); + } + return; + } + + g_signal_connect (proxy, "destroy", G_CALLBACK (on_proxy_destroy), manager); + + dbus_g_proxy_add_signal (proxy, + "SessionAdded", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_add_signal (proxy, + "SessionRemoved", + DBUS_TYPE_G_OBJECT_PATH, + G_TYPE_INVALID); + dbus_g_proxy_connect_signal (proxy, + "SessionAdded", + G_CALLBACK (seat_session_added), + manager, + NULL); + dbus_g_proxy_connect_signal (proxy, + "SessionRemoved", + G_CALLBACK (seat_session_removed), + manager, + NULL); + manager->priv->seat_proxy = proxy; + +} + +/** + * gdm_manager_get_user: + * @manager: the manager to query. + * @username: the login name of the user to get. + * + * Retrieves a pointer to the #GdmUser object for the login named @username + * from @manager. This pointer is not a reference, and should not be released. + * + * Returns: a pointer to a #GdmUser object. + **/ +GdmUser * +gdm_user_manager_get_user (GdmUserManager *manager, + const char *username) +{ + GdmUser *user; + + g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL); + g_return_val_if_fail (username != NULL && username[0] != '\0', NULL); + + user = g_hash_table_lookup (manager->priv->users, username); + + if (user == NULL) { + struct passwd *pwent; + + pwent = getpwnam (username); + + if (pwent != NULL) { + user = add_new_user_for_pwent (manager, pwent); + } + } + + return user; +} + +GdmUser * +gdm_user_manager_get_user_by_uid (GdmUserManager *manager, + uid_t uid) +{ + GdmUser *user; + struct passwd *pwent; + + g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL); + + pwent = getpwuid (uid); + if (pwent == NULL) { + g_warning ("GdmUserManager: unable to lookup uid %d", (int)uid); + return NULL; + } + + user = g_hash_table_lookup (manager->priv->users, pwent->pw_name); + + if (user == NULL) { + user = add_new_user_for_pwent (manager, pwent); + } + + return user; +} + +static void +listify_hash_values_hfunc (gpointer key, + gpointer value, + gpointer user_data) +{ + GSList **list = user_data; + + *list = g_slist_prepend (*list, value); +} + +GSList * +gdm_user_manager_list_users (GdmUserManager *manager) +{ + GSList *retval; + + g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL); + + retval = NULL; + g_hash_table_foreach (manager->priv->users, listify_hash_values_hfunc, &retval); + + return g_slist_sort (retval, (GCompareFunc) gdm_user_collate); +} + +static gboolean +parse_value_as_ulong (const char *value, + gulong *ulongval) +{ + char *end_of_valid_long; + glong long_value; + gulong ulong_value; + + errno = 0; + long_value = strtol (value, &end_of_valid_long, 10); + + if (*value == '\0' || *end_of_valid_long != '\0') { + return FALSE; + } + + ulong_value = long_value; + if (ulong_value != long_value || errno == ERANGE) { + return FALSE; + } + + *ulongval = ulong_value; + + return TRUE; +} + +static gboolean +parse_ck_history_line (const char *line, + char **user_namep, + gulong *frequencyp) +{ + GRegex *re; + GMatchInfo *match_info; + gboolean res; + gboolean ret; + GError *error; + + ret = FALSE; + re = NULL; + match_info = NULL; + + error = NULL; + re = g_regex_new ("(?P[0-9a-zA-Z]+)[ ]+(?P[0-9]+)", 0, 0, &error); + if (re == NULL) { + if (error != NULL) { + g_critical ("%s", error->message); + } else { + g_critical ("Error in regex call"); + } + goto out; + } + + g_regex_match (re, line, 0, &match_info); + + res = g_match_info_matches (match_info); + if (! res) { + g_warning ("Unable to parse history: %s", line); + goto out; + } + + if (user_namep != NULL) { + *user_namep = g_match_info_fetch_named (match_info, "username"); + } + + if (frequencyp != NULL) { + char *freq; + freq = g_match_info_fetch_named (match_info, "frequency"); + res = parse_value_as_ulong (freq, frequencyp); + g_free (freq); + if (! res) { + goto out; + } + } + + ret = TRUE; + + out: + if (match_info != NULL) { + g_match_info_free (match_info); + } + if (re != NULL) { + g_regex_unref (re); + } + return ret; +} + +static void +process_ck_history_line (GdmUserManager *manager, + const char *line) +{ + gboolean res; + char *username; + gulong frequency; + struct passwd *pwent; + GdmUser *user; + + frequency = 0; + username = NULL; + res = parse_ck_history_line (line, &username, &frequency); + if (! res) { + return; + } + + if (user_in_exclude_list (manager, username)) { + g_debug ("GdmUserManager: excluding user '%s'", username); + g_free (username); + return; + } + + /* do not show system users; we cannot use gdm_user_manager_get_user() + * here since this creates/signals users as a side effect */ + pwent = getpwnam (username); + if (pwent == NULL) { + g_warning ("Unable to lookup user name %s: %s", username, g_strerror (errno)); + return; + } + if (pwent->pw_uid < DEFAULT_MINIMAL_UID) { + g_debug ("GdmUserManager: excluding user '%s'", username); + return; + } + + user = gdm_user_manager_get_user (manager, username); + if (user == NULL) { + g_debug ("GdmUserManager: unable to lookup user '%s'", username); + g_free (username); + return; + } + + g_object_set (user, "login-frequency", frequency, NULL); + g_signal_emit (manager, signals [USER_UPDATED], 0, gdm_user_get_uid (user)); + g_free (username); +} + +static gboolean +ck_history_watch (GIOChannel *source, + GIOCondition condition, + GdmUserManager *manager) +{ + GIOStatus status; + gboolean done = FALSE; + + g_return_val_if_fail (manager != NULL, FALSE); + + if (condition & G_IO_IN) { + char *str; + GError *error; + + error = NULL; + status = g_io_channel_read_line (source, &str, NULL, NULL, &error); + if (error != NULL) { + g_warning ("GdmUserManager: unable to read line: %s", error->message); + g_error_free (error); + } + + if (status == G_IO_STATUS_NORMAL) { + g_debug ("GdmUserManager: history output: %s", str); + process_ck_history_line (manager, str); + } else if (status == G_IO_STATUS_EOF) { + done = TRUE; + } + + g_free (str); + } else if (condition & G_IO_HUP) { + done = TRUE; + } + + if (done) { + FILE *fp; + + /* Cache login counts */ + fp = fopen (LOGIN_CACHE_FILE, "w"); + if (fp != NULL) { + GHashTableIter iter; + gpointer value; + + g_hash_table_iter_init (&iter, manager->priv->users); + while (g_hash_table_iter_next (&iter, NULL, &value)) { + GdmUser *user = (GdmUser *) value; + fprintf (fp, "%s %lu\n", + gdm_user_get_user_name (user), + gdm_user_get_login_frequency (user)); + } + fclose (fp); + } + else + g_warning ("Unable to write to login cache file: %s", LOGIN_CACHE_FILE); + + if (manager->priv->loading_users) { + g_signal_emit (G_OBJECT (manager), signals[USERS_LOADED], 0); + manager->priv->loading_users = FALSE; + } + + manager->priv->ck_history_id = 0; + return FALSE; + } + + return TRUE; +} + +static void +reload_ck_history (GdmUserManager *manager) +{ + char *command; + const char *seat_id; + GError *error; + gboolean res; + char **argv; + int standard_out; + GIOChannel *channel; + + seat_id = NULL; + if (manager->priv->seat_id != NULL + && g_str_has_prefix (manager->priv->seat_id, "/org/freedesktop/ConsoleKit/")) { + + seat_id = manager->priv->seat_id + strlen ("/org/freedesktop/ConsoleKit/"); + } + + if (seat_id == NULL) { + g_warning ("Unable to find users: no seat-id found"); + return; + } + + command = g_strdup_printf ("ck-history --frequent --seat='%s' --session-type=''", + seat_id); + g_debug ("GdmUserManager: running '%s'", command); + error = NULL; + if (! g_shell_parse_argv (command, NULL, &argv, &error)) { + if (error != NULL) { + g_warning ("Could not parse command: %s", error->message); + g_error_free (error); + } else { + g_warning ("Could not parse command"); + } + goto out; + } + + error = NULL; + res = g_spawn_async_with_pipes (NULL, + argv, + NULL, + G_SPAWN_SEARCH_PATH, + NULL, + NULL, + NULL, /* pid */ + NULL, + &standard_out, + NULL, + &error); + g_strfreev (argv); + if (! res) { + if (error != NULL) { + g_warning ("Unable to run ck-history: %s", error->message); + g_error_free (error); + } else { + g_warning ("Unable to run ck-history"); + } + goto out; + } + + channel = g_io_channel_unix_new (standard_out); + g_io_channel_set_close_on_unref (channel, TRUE); + g_io_channel_set_flags (channel, + g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, + NULL); + manager->priv->ck_history_id = g_io_add_watch (channel, + G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, + (GIOFunc)ck_history_watch, + manager); + g_io_channel_unref (channel); + + out: + g_free (command); +} + +static void +add_included_user (char *username, GdmUserManager *manager) +{ + GdmUser *user; + + g_debug ("Adding included user %s", username); + /* + * The call to gdm_user_manager_get_user will add the user if it is + * valid and not already in the hash. + */ + user = gdm_user_manager_get_user (manager, username); + if (user == NULL) { + g_debug ("GdmUserManager: unable to lookup user '%s'", username); + g_free (username); + return; + } +} + +static void +add_included_users (GdmUserManager *manager) +{ + /* Add users who are specifically included */ + if (manager->priv->include != NULL) { + g_slist_foreach (manager->priv->include, + (GFunc)add_included_user, + (gpointer)manager); + } +} + +static void +reload_passwd (GdmUserManager *manager) +{ + struct passwd *pwent; + GSList *old_users; + GSList *new_users; + GSList *list; + GSList *dup; + FILE *fp; + + old_users = NULL; + new_users = NULL; + + errno = 0; + fp = fopen (PATH_PASSWD, "r"); + if (fp == NULL) { + g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno)); + goto out; + } + + g_hash_table_foreach (manager->priv->users, listify_hash_values_hfunc, &old_users); + g_slist_foreach (old_users, (GFunc) g_object_ref, NULL); + + /* Make sure we keep users who are logged in no matter what. */ + for (list = old_users; list; list = list->next) { + if (gdm_user_get_num_sessions (list->data) > 0) { + g_object_freeze_notify (G_OBJECT (list->data)); + //_gdm_user_show_short_display_name (list->data); + new_users = g_slist_prepend (new_users, g_object_ref (list->data)); + } + } + + if (manager->priv->include_all != TRUE) { + g_debug ("GdmUserManager: include_all is FALSE"); + } else { + g_debug ("GdmUserManager: include_all is TRUE"); + + for (pwent = fgetpwent (fp); + pwent != NULL; + pwent = fgetpwent (fp)) { + GdmUser *user; + + user = NULL; + + /* Skip users below MinimalUID... */ + if (pwent->pw_uid < DEFAULT_MINIMAL_UID) { + continue; + } + + /* ...And users w/ invalid shells... */ + if (pwent->pw_shell == NULL || + !g_hash_table_lookup (manager->priv->shells, + pwent->pw_shell)) { + g_debug ("GdmUserManager: skipping user with bad shell: %s", pwent->pw_name); + continue; + } + + /* ...And explicitly excluded users */ + if (user_in_exclude_list (manager, pwent->pw_name)) { + g_debug ("GdmUserManager: explicitly skipping user: %s", pwent->pw_name); + continue; + } + + user = g_hash_table_lookup (manager->priv->users, + pwent->pw_name); + + /* Update users already in the *new* list */ + if (g_slist_find (new_users, user)) { + _gdm_user_update (user, pwent); + continue; + } + + if (user == NULL) { + user = create_user (manager); + } else { + g_object_ref (user); + } + + /* Freeze & update users not already in the new list */ + g_object_freeze_notify (G_OBJECT (user)); + _gdm_user_update (user, pwent); + + new_users = g_slist_prepend (new_users, user); + } + } + + /* Go through and handle removed users */ + for (list = old_users; list; list = list->next) { + if (! g_slist_find (new_users, list->data)) { + g_signal_emit (manager, signals[USER_REMOVED], 0, gdm_user_get_uid (GDM_USER (list->data))); + g_hash_table_remove (manager->priv->users, + gdm_user_get_user_name (list->data)); + } + } + + /* Go through and handle added users or update display names */ + for (list = new_users; list; list = list->next) { + if (g_slist_find (old_users, list->data)) { + dup = g_slist_find_custom (new_users, + list->data, + match_real_name_cmpfunc); + if (dup != NULL) { + //_gdm_user_show_full_display_name (list->data); + //_gdm_user_show_full_display_name (dup->data); + } + } else { + add_user (manager, list->data); + } + } + + add_included_users (manager); + + if (!manager->priv->loaded_passwd) { + g_signal_emit (manager, signals[USERS_LOADED], 0); + manager->priv->loaded_passwd = TRUE; + } + + out: + /* Cleanup */ + + fclose (fp); + + g_slist_foreach (new_users, (GFunc) g_object_thaw_notify, NULL); + g_slist_foreach (new_users, (GFunc) g_object_unref, NULL); + g_slist_free (new_users); + + g_slist_foreach (old_users, (GFunc) g_object_unref, NULL); + g_slist_free (old_users); +} + +static void +load_login_frequency_cache (GdmUserManager *manager) +{ + GIOChannel *channel; + gchar *line; + + channel = g_io_channel_new_file (LOGIN_CACHE_FILE, "r", NULL); + if (channel == NULL) + return; + + while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) { + process_ck_history_line (manager, line); + g_free (line); + } + + g_io_channel_close (channel); + + if (manager->priv->loading_users) { + g_signal_emit (G_OBJECT (manager), signals[USERS_LOADED], 0); + manager->priv->loading_users = FALSE; + } +} + +static void +reload_users (GdmUserManager *manager) +{ + if (!manager->priv->loaded_cache) { + load_login_frequency_cache (manager); + manager->priv->loaded_cache = TRUE; + } + reload_ck_history (manager); + reload_passwd (manager); +} + +static gboolean +reload_users_timeout (GdmUserManager *manager) +{ + reload_users (manager); + manager->priv->reload_id = 0; + + return FALSE; +} + +static void +queue_reload_users (GdmUserManager *manager) +{ + if (manager->priv->reload_id > 0) { + return; + } + + g_signal_emit (G_OBJECT (manager), signals[LOADING_USERS], 0); + manager->priv->loading_users = TRUE; + manager->priv->reload_id = g_idle_add ((GSourceFunc)reload_users_timeout, manager); +} + +static void +reload_shells (GdmUserManager *manager) +{ + char *shell; + + setusershell (); + + g_hash_table_remove_all (manager->priv->shells); + for (shell = getusershell (); shell != NULL; shell = getusershell ()) { + /* skip well known not-real shells */ + if (shell == NULL + || strcmp (shell, "/sbin/nologin") == 0 + || strcmp (shell, "/bin/false") == 0) { + g_debug ("GdmUserManager: skipping shell %s", shell); + continue; + } + g_hash_table_insert (manager->priv->shells, + g_strdup (shell), + GUINT_TO_POINTER (TRUE)); + } + + endusershell (); +} + +static void +on_shells_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + GdmUserManager *manager) +{ + if (event_type != G_FILE_MONITOR_EVENT_CHANGED && + event_type != G_FILE_MONITOR_EVENT_CREATED) { + return; + } + + reload_shells (manager); + reload_passwd (manager); +} + +static void +on_passwd_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + GdmUserManager *manager) +{ + if (event_type != G_FILE_MONITOR_EVENT_CHANGED && + event_type != G_FILE_MONITOR_EVENT_CREATED) { + return; + } + + reload_passwd (manager); +} + +static void +gdm_user_manager_class_init (GdmUserManagerClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->finalize = gdm_user_manager_finalize; + + signals [LOADING_USERS] = + g_signal_new ("loading-users", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserManagerClass, loading_users), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [USERS_LOADED] = + g_signal_new ("users-loaded", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserManagerClass, users_loaded), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + signals [USER_ADDED] = + g_signal_new ("user-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserManagerClass, user_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_INT64); + signals [USER_REMOVED] = + g_signal_new ("user-removed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserManagerClass, user_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_INT64); + signals [USER_UPDATED] = + g_signal_new ("user-updated", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GdmUserManagerClass, user_updated), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_INT64); + + g_type_class_add_private (klass, sizeof (GdmUserManagerPrivate)); + + dbus_g_object_type_install_info (GDM_TYPE_USER_MANAGER, &dbus_glib_gdm_user_manager_object_info); +} + +static void +gdm_set_string_list (char *value, GSList **retval) +{ + char **temp_array; + int i; + + *retval = NULL; + + if (value == NULL || *value == '\0') { + g_debug ("Not adding NULL user"); + *retval = NULL; + return; + } + + temp_array = g_strsplit (value, ",", 0); + for (i = 0; temp_array[i] != NULL; i++) { + g_debug ("Adding value %s", temp_array[i]); + g_strstrip (temp_array[i]); + *retval = g_slist_prepend (*retval, g_strdup (temp_array[i])); + } + + g_strfreev (temp_array); +} + +static void +gdm_user_manager_init (GdmUserManager *manager) +{ + int i; + GFile *file; + GError *error; + char *temp; + gboolean res; + + manager->priv = GDM_USER_MANAGER_GET_PRIVATE (manager); + + /* exclude/include */ + g_debug ("Setting users to include:"); + res = gdm_settings_direct_get_string (GDM_KEY_INCLUDE, + &temp); + gdm_set_string_list (temp, &manager->priv->include); + + g_debug ("Setting users to exclude:"); + res = gdm_settings_direct_get_string (GDM_KEY_EXCLUDE, + &temp); + gdm_set_string_list (temp, &manager->priv->exclude); + + res = gdm_settings_direct_get_boolean (GDM_KEY_INCLUDE_ALL, + &manager->priv->include_all); + + /* sessions */ + manager->priv->sessions = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); + + /* users */ + manager->priv->users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) g_object_run_dispose); + + if (manager->priv->include_all == TRUE) { + /* /etc/shells */ + manager->priv->shells = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + reload_shells (manager); + file = g_file_new_for_path (_PATH_SHELLS); + error = NULL; + manager->priv->shells_monitor = g_file_monitor_file (file, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (manager->priv->shells_monitor != NULL) { + g_signal_connect (manager->priv->shells_monitor, + "changed", + G_CALLBACK (on_shells_monitor_changed), + manager); + } else { + g_warning ("Unable to monitor %s: %s", _PATH_SHELLS, error->message); + g_error_free (error); + } + g_object_unref (file); + + /* /etc/passwd */ + file = g_file_new_for_path (PATH_PASSWD); + manager->priv->passwd_monitor = g_file_monitor_file (file, + G_FILE_MONITOR_NONE, + NULL, + &error); + if (manager->priv->passwd_monitor != NULL) { + g_signal_connect (manager->priv->passwd_monitor, + "changed", + G_CALLBACK (on_passwd_monitor_changed), + manager); + } else { + g_warning ("Unable to monitor %s: %s", PATH_PASSWD, error->message); + g_error_free (error); + } + g_object_unref (file); + } + + get_seat_proxy (manager); + + queue_reload_users (manager); + + manager->priv->users_dirty = FALSE; + + dbus_g_connection_register_g_object (manager->priv->connection, GDM_USER_MANAGER_DBUS_PATH, G_OBJECT (manager)); +} + +static void +gdm_user_manager_finalize (GObject *object) +{ + GdmUserManager *manager; + + g_return_if_fail (object != NULL); + g_return_if_fail (GDM_IS_USER_MANAGER (object)); + + manager = GDM_USER_MANAGER (object); + + g_return_if_fail (manager->priv != NULL); + + if (manager->priv->exclude != NULL) { + g_slist_free (manager->priv->exclude); + } + + if (manager->priv->include != NULL) { + g_slist_free (manager->priv->include); + } + + if (manager->priv->seat_proxy != NULL) { + g_object_unref (manager->priv->seat_proxy); + } + + if (manager->priv->ck_history_id != 0) { + g_source_remove (manager->priv->ck_history_id); + manager->priv->ck_history_id = 0; + } + + if (manager->priv->reload_id > 0) { + g_source_remove (manager->priv->reload_id); + manager->priv->reload_id = 0; + } + + g_hash_table_destroy (manager->priv->sessions); + + g_file_monitor_cancel (manager->priv->passwd_monitor); + g_hash_table_destroy (manager->priv->users); + + g_file_monitor_cancel (manager->priv->shells_monitor); + g_hash_table_destroy (manager->priv->shells); + + g_free (manager->priv->seat_id); + + G_OBJECT_CLASS (gdm_user_manager_parent_class)->finalize (object); +} + +GdmUserManager * +gdm_user_manager_ref_default (void) +{ + if (user_manager_object != NULL) { + g_object_ref (user_manager_object); + } else { + user_manager_object = g_object_new (GDM_TYPE_USER_MANAGER, NULL); + g_object_add_weak_pointer (user_manager_object, + (gpointer *) &user_manager_object); + } + + return GDM_USER_MANAGER (user_manager_object); +} + +/* + Example: + dbus-send --system --print-reply --dest=org.gnome.DisplayManager \ + /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.CountUsers +*/ +gboolean +gdm_user_manager_count_users (GdmUserManager *user_manager, + gint *user_count, + GError **error) +{ + *user_count = g_hash_table_size (user_manager->priv->users); + + return TRUE; +} + +/* + Example: + dbus-send --system --print-reply --dest=org.gnome.DisplayManager \ + /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUserList +*/ +gboolean +gdm_user_manager_get_user_list (GdmUserManager *user_manager, + GArray **user_list, + GError **error) +{ + GHashTableIter iter; + GdmUser *user; + + *user_list = g_array_new (FALSE, FALSE, sizeof (gint64)); + g_hash_table_iter_init (&iter, user_manager->priv->users); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&user)) { + gint64 uid = gdm_user_get_uid (user); + g_array_append_val (*user_list, uid); + } + + return TRUE; +} + + +/* + Example: + dbus-send --system --print-reply --dest=org.gnome.DisplayManager \ + /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUserInfo int64:1000 +*/ +gboolean +gdm_user_manager_get_user_info (GdmUserManager *user_manager, + gint64 uid, + gchar **user_name, + gchar **real_name, + gchar **shell, + gint *login_count, + gchar **icon_url, + GError **error) +{ + GdmUser *user; + + user = gdm_user_manager_get_user_by_uid (user_manager, uid); + if (user == NULL) + return FALSE; + + *user_name = g_strdup (gdm_user_get_user_name (user)); + *real_name = g_strdup (gdm_user_get_real_name (user)); + *login_count = gdm_user_get_login_frequency (user); + *shell = g_strdup (gdm_user_get_shell (user)); + *icon_url = g_strdup (gdm_user_get_icon_url (user)); + + return TRUE; +} + +/* + Example: + dbus-send --system --print-reply --dest=org.gnome.DisplayManager \ + /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUsersInfo array:int64:1000,1001 +*/ +gboolean +gdm_user_manager_get_users_info (GdmUserManager *user_manager, + GArray *uids, + GPtrArray **users_info, + GError **error) +{ + int i; + + *users_info = g_ptr_array_new (); + + for (i = 0; i < uids->len; i++) { + gint64 uid; + GdmUser *user; + GValueArray *user_info; + GValue arg = {0}; + + uid = g_array_index (uids, gint64, i); + user = gdm_user_manager_get_user_by_uid (user_manager, uid); + if (user == NULL) + continue; + + user_info = g_value_array_new (5); + + g_value_init (&arg, G_TYPE_INT64); + g_value_set_int64 (&arg, uid); + g_value_array_append (user_info, &arg); + g_value_unset (&arg); + + g_value_init (&arg, G_TYPE_STRING); + g_value_set_string (&arg, gdm_user_get_user_name (user)); + g_value_array_append (user_info, &arg); + g_value_unset (&arg); + + g_value_init (&arg, G_TYPE_STRING); + g_value_set_string (&arg, gdm_user_get_real_name (user)); + g_value_array_append (user_info, &arg); + g_value_unset (&arg); + + g_value_init (&arg, G_TYPE_STRING); + g_value_set_string (&arg, gdm_user_get_shell (user)); + g_value_array_append (user_info, &arg); + g_value_unset (&arg); + + g_value_init (&arg, G_TYPE_INT); + g_value_set_int (&arg, gdm_user_get_login_frequency (user)); + g_value_array_append (user_info, &arg); + g_value_unset (&arg); + + g_value_init (&arg, G_TYPE_STRING); + g_value_set_string (&arg, gdm_user_get_icon_url (user)); + g_value_array_append (user_info, &arg); + g_value_unset (&arg); + + g_ptr_array_add (*users_info, user_info); + } + + return TRUE; +} + +/* + Example: + dbus-send --system --print-reply --dest=org.gnome.DisplayManager \ + /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUsersLoaded +*/ +gboolean +gdm_user_manager_get_users_loaded (GdmUserManager *user_manager, + gboolean *is_loaded, + GError **error) +{ + *is_loaded = user_manager->priv->loaded_passwd; + return TRUE; +} diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/gdm-user-manager.h gdm-2.30.2.new/daemon/gdm-user-manager.h --- gdm-2.30.2/daemon/gdm-user-manager.h 1970-01-01 10:00:00.000000000 +1000 +++ gdm-2.30.2.new/daemon/gdm-user-manager.h 2010-06-09 14:09:08.137025806 +1000 @@ -0,0 +1,106 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2007 William Jon McCann + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __GDM_USER_MANAGER_H +#define __GDM_USER_MANAGER_H + +#include + +#include "gdm-user.h" + +G_BEGIN_DECLS + +#define GDM_TYPE_USER_MANAGER (gdm_user_manager_get_type ()) +#define GDM_USER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_MANAGER, GdmUserManager)) +#define GDM_USER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_MANAGER, GdmUserManagerClass)) +#define GDM_IS_USER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_MANAGER)) +#define GDM_IS_USER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_MANAGER)) +#define GDM_USER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerClass)) + +typedef struct GdmUserManagerPrivate GdmUserManagerPrivate; + +typedef struct +{ + GObject parent; + GdmUserManagerPrivate *priv; +} GdmUserManager; + +typedef struct +{ + GObjectClass parent_class; + + void (* loading_users) (GdmUserManager *user_manager); + void (* users_loaded) (GdmUserManager *user_manager); + void (* user_added) (GdmUserManager *user_manager, + gint64 uid); + void (* user_removed) (GdmUserManager *user_manager, + gint64 uid); + void (* user_updated) (GdmUserManager *user_manager, + gint64 uid); +} GdmUserManagerClass; + +typedef enum +{ + GDM_USER_MANAGER_ERROR_GENERAL, + GDM_USER_MANAGER_ERROR_KEY_NOT_FOUND +} GdmUserManagerError; + +#define GDM_USER_MANAGER_ERROR gdm_user_manager_error_quark () + +GQuark gdm_user_manager_error_quark (void); +GType gdm_user_manager_get_type (void); + +GdmUserManager * gdm_user_manager_ref_default (void); + +GSList * gdm_user_manager_list_users (GdmUserManager *manager); +GdmUser * gdm_user_manager_get_user (GdmUserManager *manager, + const char *user_name); +GdmUser * gdm_user_manager_get_user_by_uid (GdmUserManager *manager, + uid_t uid); + +gboolean gdm_user_manager_count_users (GdmUserManager *user_manager, + gint *user_count, + GError **error); + +gboolean gdm_user_manager_get_user_list (GdmUserManager *user_manager, + GArray **user_list, + GError **error); + +gboolean gdm_user_manager_get_user_info (GdmUserManager *user_manager, + gint64 uid, + gchar **user_name, + gchar **real_name, + gchar **shell, + gint *login_count, + gchar **icon_url, + GError **error); + +gboolean gdm_user_manager_get_users_info (GdmUserManager *user_manager, + GArray *uids, + GPtrArray **user_info, + GError **error); + +gboolean gdm_user_manager_get_users_loaded (GdmUserManager *user_manager, + gboolean *is_loaded, + GError **error); + +G_END_DECLS + +#endif /* __GDM_USER_MANAGER_H */ diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/gdm-user-manager.xml gdm-2.30.2.new/daemon/gdm-user-manager.xml --- gdm-2.30.2/daemon/gdm-user-manager.xml 1970-01-01 10:00:00.000000000 +1000 +++ gdm-2.30.2.new/daemon/gdm-user-manager.xml 2010-06-09 14:09:08.137025806 +1000 @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/gdm-user-private.h gdm-2.30.2.new/daemon/gdm-user-private.h --- gdm-2.30.2/daemon/gdm-user-private.h 1970-01-01 10:00:00.000000000 +1000 +++ gdm-2.30.2.new/daemon/gdm-user-private.h 2010-06-09 14:09:08.137025806 +1000 @@ -0,0 +1,45 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright (C) 2004-2005 James M. Cape . + * + * 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 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Private interfaces to the GdmUser object + */ + +#ifndef __GDM_USER_PRIVATE__ +#define __GDM_USER_PRIVATE__ 1 + +#include + +#include "gdm-user.h" + +G_BEGIN_DECLS + +void _gdm_user_update (GdmUser *user, + const struct passwd *pwent); +void _gdm_user_add_session (GdmUser *user, + const char *session_id); +void _gdm_user_remove_session (GdmUser *user, + const char *session_id); + +void _gdm_user_icon_changed (GdmUser *user); + + +G_END_DECLS + +#endif /* !__GDM_USER_PRIVATE__ */ diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/main.c gdm-2.30.2.new/daemon/main.c --- gdm-2.30.2/daemon/main.c 2010-03-18 08:27:16.000000000 +1100 +++ gdm-2.30.2.new/daemon/main.c 2010-06-09 14:09:08.137025806 +1000 @@ -43,6 +43,7 @@ #include #include +#include "gdm-user-manager.h" #include "gdm-manager.h" #include "gdm-log.h" #include "gdm-common.h" @@ -597,6 +598,8 @@ goto out; } + gdm_user_manager_ref_default (); + gdm_log_set_debug (is_debug_set ()); gdm_daemon_change_user (&gdm_uid, &gdm_gid); diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/daemon/Makefile.am gdm-2.30.2.new/daemon/Makefile.am --- gdm-2.30.2/daemon/Makefile.am 2010-03-27 00:28:03.000000000 +1100 +++ gdm-2.30.2.new/daemon/Makefile.am 2010-06-09 14:09:08.137025806 +1000 @@ -9,6 +9,7 @@ -DDATADIR=\"$(datadir)\" \ -DDMCONFDIR=\"$(dmconfdir)\" \ -DGDMCONFDIR=\"$(gdmconfdir)\" \ + -DCACHEDIR=\"$(cachedir)\" \ -DLIBDIR=\"$(libdir)\" \ -DLIBEXECDIR=\"$(libexecdir)\" \ -DLOGDIR=\"$(logdir)\" \ @@ -35,6 +36,7 @@ gdm-session-direct-glue.h \ gdm-manager-glue.h \ gdm-display-glue.h \ + gdm-user-manager-glue.h \ gdm-xdmcp-greeter-display-glue.h \ gdm-xdmcp-chooser-display-glue.h \ gdm-static-display-glue.h \ @@ -46,6 +48,8 @@ gdm-manager-glue.h: gdm-manager.xml Makefile.am dbus-binding-tool --prefix=gdm_manager --mode=glib-server --output=gdm-manager-glue.h $(srcdir)/gdm-manager.xml +gdm-user-manager-glue.h: gdm-user-manager.xml Makefile.am + dbus-binding-tool --prefix=gdm_user_manager --mode=glib-server --output=gdm-user-manager-glue.h $(srcdir)/gdm-user-manager.xml gdm-slave-glue.h: gdm-slave.xml Makefile.am dbus-binding-tool --prefix=gdm_slave --mode=glib-server --output=gdm-slave-glue.h $(srcdir)/gdm-slave.xml gdm-simple-slave-glue.h: gdm-simple-slave.xml Makefile.am @@ -298,6 +302,11 @@ gdm-product-display.h \ gdm-manager.c \ gdm-manager.h \ + gdm-user.c \ + gdm-user.h \ + gdm-user-private.h \ + gdm-user-manager.c \ + gdm-user-manager.h \ gdm-slave-proxy.c \ gdm-slave-proxy.h \ $(NULL) @@ -360,6 +369,7 @@ gdm-session-direct.xml \ gdm-manager.xml \ gdm-display.xml \ + gdm-user-manager.xml \ gdm-xdmcp-greeter-display.xml \ gdm-xdmcp-chooser-display.xml \ gdm-static-display.xml \ diff -Nur -x '*.orig' -x '*~' gdm-2.30.2/data/gdm.conf.in gdm-2.30.2.new/data/gdm.conf.in --- gdm-2.30.2/data/gdm.conf.in 2010-06-09 14:09:07.597026241 +1000 +++ gdm-2.30.2.new/data/gdm.conf.in 2010-06-09 14:09:08.137025806 +1000 @@ -8,6 +8,8 @@ + @@ -28,6 +30,8 @@ + @@ -71,6 +75,22 @@ + + + + + + +