source: proiecte/PPPP/gdm/debian/patches/16_gdmserver_user_manager.patch @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 89.2 KB
  • configure.ac

    #
    # 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 <robert.ancell@canonical.com>
    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.28.0/configure.ac gdm-2.28.0.new/configure.ac
    old new  
    7373        polkit-gobject-1 >= $POLKIT_GOBJECT_REQUIRED_VERSION
    7474        gobject-2.0 >= $GLIB_REQUIRED_VERSION
    7575        gio-2.0 >= $GLIB_REQUIRED_VERSION
     76        gconf-2.0 >= $GCONF_REQUIRED_VERSION
    7677        hal
    7778)
    7879AC_SUBST(DAEMON_CFLAGS)
     
    949950fi
    950951AC_SUBST(logdir, $GDM_LOG_DIR)
    951952
     953AC_ARG_WITH(cache-dir,
     954            AS_HELP_STRING([--with-cache-dir=<file>],
     955                           [cache dir]))
     956
     957if ! test -z "$with_cache_dir"; then
     958   GDM_CACHE_DIR=$with_cache_dir
     959else
     960   GDM_CACHE_DIR=/var/cache/gdm
     961fi
     962AC_SUBST(cachedir, $GDM_CACHE_DIR)
     963
    952964withval=""
    953965AC_ARG_WITH(at-bindir,
    954966            AS_HELP_STRING([--with-at-bindir=<PATH>]
  • daemon/gdm-user.c

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/gdm-user.c gdm-2.28.0.new/daemon/gdm-user.c
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
     4 * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
     5 *
     6 * This program is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19 */
     20
     21#include <config.h>
     22
     23#include <float.h>
     24#include <string.h>
     25#include <sys/types.h>
     26#include <sys/stat.h>
     27#include <unistd.h>
     28
     29#include <glib/gi18n.h>
     30#include <gio/gio.h>
     31
     32#include "gdm-user-manager.h"
     33#include "gdm-user-private.h"
     34
     35#define GDM_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GDM_TYPE_USER, GdmUserClass))
     36#define GDM_IS_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GDM_TYPE_USER))
     37#define GDM_USER_GET_CLASS(object) (G_TYPE_INSTANCE_GET_CLASS ((object), GDM_TYPE_USER, GdmUserClass))
     38
     39enum {
     40        PROP_0,
     41        PROP_REAL_NAME,
     42        PROP_USER_NAME,
     43        PROP_UID,
     44        PROP_HOME_DIR,
     45        PROP_SHELL,
     46        PROP_ICON_URL,       
     47        PROP_LOGIN_FREQUENCY,
     48};
     49
     50enum {
     51        ICON_CHANGED,
     52        SESSIONS_CHANGED,
     53        LAST_SIGNAL
     54};
     55
     56struct _GdmUser {
     57        GObject         parent;
     58
     59        uid_t           uid;
     60        char           *user_name;
     61        char           *real_name;
     62        char           *home_dir;
     63        char           *shell;
     64        char           *icon_url;
     65        GList          *sessions;
     66        gulong          login_frequency;
     67
     68        GFileMonitor   *icon_monitor;
     69};
     70
     71typedef struct _GdmUserClass
     72{
     73        GObjectClass parent_class;
     74
     75        void (* icon_changed)     (GdmUser *user);
     76        void (* sessions_changed) (GdmUser *user);
     77} GdmUserClass;
     78
     79static void gdm_user_finalize     (GObject      *object);
     80
     81static guint signals[LAST_SIGNAL] = { 0 };
     82
     83G_DEFINE_TYPE (GdmUser, gdm_user, G_TYPE_OBJECT)
     84
     85static int
     86session_compare (const char *a,
     87                 const char *b)
     88{
     89        if (a == NULL) {
     90                return 1;
     91        } else if (b == NULL) {
     92                return -1;
     93        }
     94
     95        return strcmp (a, b);
     96}
     97
     98void
     99_gdm_user_add_session (GdmUser    *user,
     100                       const char *ssid)
     101{
     102        GList *li;
     103
     104        g_return_if_fail (GDM_IS_USER (user));
     105        g_return_if_fail (ssid != NULL);
     106
     107        li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
     108        if (li == NULL) {
     109                g_debug ("GdmUser: adding session %s", ssid);
     110                user->sessions = g_list_prepend (user->sessions, g_strdup (ssid));
     111                g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
     112        } else {
     113                g_debug ("GdmUser: session already present: %s", ssid);
     114        }
     115}
     116
     117void
     118_gdm_user_remove_session (GdmUser    *user,
     119                          const char *ssid)
     120{
     121        GList *li;
     122
     123        g_return_if_fail (GDM_IS_USER (user));
     124        g_return_if_fail (ssid != NULL);
     125
     126        li = g_list_find_custom (user->sessions, ssid, (GCompareFunc)session_compare);
     127        if (li != NULL) {
     128                g_debug ("GdmUser: removing session %s", ssid);
     129                g_free (li->data);
     130                user->sessions = g_list_delete_link (user->sessions, li);
     131                g_signal_emit (user, signals[SESSIONS_CHANGED], 0);
     132        } else {
     133                g_debug ("GdmUser: session not found: %s", ssid);
     134        }
     135}
     136
     137guint
     138gdm_user_get_num_sessions (GdmUser    *user)
     139{
     140        return g_list_length (user->sessions);
     141}
     142
     143GList *
     144gdm_user_get_sessions (GdmUser *user)
     145{
     146        return user->sessions;
     147}
     148
     149static void
     150gdm_user_set_property (GObject      *object,
     151                       guint         param_id,
     152                       const GValue *value,
     153                       GParamSpec   *pspec)
     154{
     155        GdmUser *user;
     156
     157        user = GDM_USER (object);
     158
     159        switch (param_id) {
     160        case PROP_LOGIN_FREQUENCY:
     161                user->login_frequency = g_value_get_ulong (value);
     162                g_object_notify (G_OBJECT (user), "login-frequency");
     163                break;
     164        default:
     165                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
     166                break;
     167        }
     168}
     169
     170static void
     171gdm_user_get_property (GObject    *object,
     172                       guint       param_id,
     173                       GValue     *value,
     174                       GParamSpec *pspec)
     175{
     176        GdmUser *user;
     177
     178        user = GDM_USER (object);
     179
     180        switch (param_id) {
     181        case PROP_USER_NAME:
     182                g_value_set_string (value, user->user_name);
     183                break;
     184        case PROP_REAL_NAME:
     185                g_value_set_string (value, user->real_name);
     186                break;
     187        case PROP_HOME_DIR:
     188                g_value_set_string (value, user->home_dir);
     189                break;
     190        case PROP_UID:
     191                g_value_set_ulong (value, user->uid);
     192                break;
     193        case PROP_SHELL:
     194                g_value_set_string (value, user->shell);
     195                break;
     196        case PROP_ICON_URL:
     197                g_value_set_string (value, user->icon_url);
     198                break;           
     199        case PROP_LOGIN_FREQUENCY:
     200                g_value_set_ulong (value, user->login_frequency);
     201                break;
     202        default:
     203                G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
     204                break;
     205        }
     206}
     207
     208static void
     209gdm_user_class_init (GdmUserClass *class)
     210{
     211        GObjectClass *gobject_class;
     212
     213        gobject_class = G_OBJECT_CLASS (class);
     214
     215        gobject_class->set_property = gdm_user_set_property;
     216        gobject_class->get_property = gdm_user_get_property;
     217        gobject_class->finalize = gdm_user_finalize;
     218
     219        g_object_class_install_property (gobject_class,
     220                                         PROP_REAL_NAME,
     221                                         g_param_spec_string ("real-name",
     222                                                              "Real Name",
     223                                                              "The real name to display for this user.",
     224                                                              NULL,
     225                                                              G_PARAM_READABLE));
     226
     227        g_object_class_install_property (gobject_class,
     228                                         PROP_UID,
     229                                         g_param_spec_ulong ("uid",
     230                                                             "User ID",
     231                                                             "The UID for this user.",
     232                                                             0, G_MAXULONG, 0,
     233                                                             G_PARAM_READABLE));
     234        g_object_class_install_property (gobject_class,
     235                                         PROP_USER_NAME,
     236                                         g_param_spec_string ("user-name",
     237                                                              "User Name",
     238                                                              "The login name for this user.",
     239                                                              NULL,
     240                                                              G_PARAM_READABLE));
     241        g_object_class_install_property (gobject_class,
     242                                         PROP_HOME_DIR,
     243                                         g_param_spec_string ("home-directory",
     244                                                              "Home Directory",
     245                                                              "The home directory for this user.",
     246                                                              NULL,
     247                                                              G_PARAM_READABLE));
     248        g_object_class_install_property (gobject_class,
     249                                         PROP_SHELL,
     250                                         g_param_spec_string ("shell",
     251                                                              "Shell",
     252                                                              "The shell for this user.",
     253                                                              NULL,
     254                                                              G_PARAM_READABLE));
     255        g_object_class_install_property (gobject_class,
     256                                         PROP_SHELL,
     257                                         g_param_spec_string ("icon-url",
     258                                                              "Icon URL",
     259                                                              "The icon for this user.",
     260                                                              NULL,
     261                                                              G_PARAM_READABLE));
     262        g_object_class_install_property (gobject_class,
     263                                         PROP_LOGIN_FREQUENCY,
     264                                         g_param_spec_ulong ("login-frequency",
     265                                                             "login frequency",
     266                                                             "login frequency",
     267                                                             0,
     268                                                             G_MAXULONG,
     269                                                             0,
     270                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
     271
     272        signals [ICON_CHANGED] =
     273                g_signal_new ("icon-changed",
     274                              G_TYPE_FROM_CLASS (class),
     275                              G_SIGNAL_RUN_LAST,
     276                              G_STRUCT_OFFSET (GdmUserClass, icon_changed),
     277                              NULL, NULL,
     278                              g_cclosure_marshal_VOID__VOID,
     279                              G_TYPE_NONE, 0);
     280        signals [SESSIONS_CHANGED] =
     281                g_signal_new ("sessions-changed",
     282                              G_TYPE_FROM_CLASS (class),
     283                              G_SIGNAL_RUN_LAST,
     284                              G_STRUCT_OFFSET (GdmUserClass, sessions_changed),
     285                              NULL, NULL,
     286                              g_cclosure_marshal_VOID__VOID,
     287                              G_TYPE_NONE, 0);
     288}
     289
     290
     291static void
     292on_icon_monitor_changed (GFileMonitor     *monitor,
     293                         GFile            *file,
     294                         GFile            *other_file,
     295                         GFileMonitorEvent event_type,
     296                         GdmUser          *user)
     297{
     298        g_debug ("Icon changed: %d", event_type);
     299
     300        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
     301            event_type != G_FILE_MONITOR_EVENT_CREATED) {
     302                return;
     303        }
     304
     305        g_signal_emit (user, signals[ICON_CHANGED], 0);
     306}
     307
     308static void
     309update_icon_monitor (GdmUser *user)
     310{
     311        GFile  *file;
     312        GError *error = NULL;
     313
     314        if (user->icon_url != NULL) {
     315                g_free (user->icon_url);
     316                user->icon_url = NULL;
     317        }
     318        if (user->home_dir != NULL) {
     319                gchar *filename;
     320                filename = g_build_filename (user->home_dir, ".face", NULL);
     321                user->icon_url = g_strjoin(NULL, "file://", filename, NULL);
     322                g_free (filename);
     323        }
     324        g_object_notify (G_OBJECT (user), "icon-url");
     325
     326        if (user->icon_monitor != NULL) {
     327                g_file_monitor_cancel (user->icon_monitor);
     328                user->icon_monitor = NULL;
     329        }
     330
     331        if (user->icon_url == NULL) {
     332                return;
     333        }
     334
     335        g_debug ("adding monitor for '%s'", user->icon_url);
     336        file = g_file_new_for_uri (user->icon_url);
     337        user->icon_monitor = g_file_monitor_file (file,
     338                                                  G_FILE_MONITOR_NONE,
     339                                                  NULL,
     340                                                  &error);
     341        if (user->icon_monitor != NULL) {
     342                g_signal_connect (user->icon_monitor,
     343                                  "changed",
     344                                  G_CALLBACK (on_icon_monitor_changed),
     345                                  user);
     346        } else {
     347                g_warning ("Unable to monitor %s: %s", user->icon_url, error->message);
     348                g_error_free (error);
     349        }
     350        g_object_unref (file);
     351}
     352
     353static void
     354gdm_user_init (GdmUser *user)
     355{
     356        user->user_name = NULL;
     357        user->real_name = NULL;
     358        user->sessions = NULL;
     359}
     360
     361static void
     362gdm_user_finalize (GObject *object)
     363{
     364        GdmUser *user;
     365
     366        user = GDM_USER (object);
     367
     368        g_file_monitor_cancel (user->icon_monitor);
     369
     370        g_free (user->user_name);
     371        g_free (user->real_name);
     372
     373        if (G_OBJECT_CLASS (gdm_user_parent_class)->finalize)
     374                (*G_OBJECT_CLASS (gdm_user_parent_class)->finalize) (object);
     375}
     376
     377/**
     378 * _gdm_user_update:
     379 * @user: the user object to update.
     380 * @pwent: the user data to use.
     381 *
     382 * Updates the properties of @user using the data in @pwent.
     383 *
     384 * Since: 1.0
     385 **/
     386void
     387_gdm_user_update (GdmUser             *user,
     388                  const struct passwd *pwent)
     389{
     390        gchar *real_name;
     391
     392        g_return_if_fail (GDM_IS_USER (user));
     393        g_return_if_fail (pwent != NULL);
     394
     395        g_object_freeze_notify (G_OBJECT (user));
     396
     397        /* Display Name */
     398        if (pwent->pw_gecos && pwent->pw_gecos[0] != '\0') {
     399                gchar *first_comma;
     400                gchar *real_name_utf8;
     401
     402                real_name_utf8 = g_locale_to_utf8 (pwent->pw_gecos, -1, NULL, NULL, NULL);
     403
     404                first_comma = strchr (real_name_utf8, ',');
     405                if (first_comma) {
     406                        real_name = g_strndup (real_name_utf8, first_comma - real_name_utf8);
     407                        g_free (real_name_utf8);
     408                } else {
     409                        real_name = real_name_utf8;
     410                }
     411
     412                if (real_name[0] == '\0') {
     413                        g_free (real_name);
     414                        real_name = NULL;
     415                }
     416        } else {
     417                real_name = NULL;
     418        }
     419
     420        if ((real_name && !user->real_name) ||
     421            (!real_name && user->real_name) ||
     422            (real_name &&
     423             user->real_name &&
     424             strcmp (real_name, user->real_name) != 0)) {
     425                g_free (user->real_name);
     426                user->real_name = real_name;
     427                g_object_notify (G_OBJECT (user), "real-name");
     428        } else {
     429                g_free (real_name);
     430        }
     431
     432        /* UID */
     433        if (pwent->pw_uid != user->uid) {
     434                user->uid = pwent->pw_uid;
     435                g_object_notify (G_OBJECT (user), "uid");
     436        }
     437
     438        /* Username */
     439        if ((pwent->pw_name && !user->user_name) ||
     440            (!pwent->pw_name && user->user_name) ||
     441            (pwent->pw_name &&
     442             user->user_name &&
     443             strcmp (user->user_name, pwent->pw_name) != 0)) {
     444                g_free (user->user_name);
     445                user->user_name = g_strdup (pwent->pw_name);
     446                g_object_notify (G_OBJECT (user), "user-name");
     447        }
     448
     449        /* Home Directory */
     450        if ((pwent->pw_dir && !user->home_dir) ||
     451            (!pwent->pw_dir && user->home_dir) ||
     452            strcmp (user->home_dir, pwent->pw_dir) != 0) {
     453                g_free (user->home_dir);
     454                user->home_dir = g_strdup (pwent->pw_dir);
     455                g_object_notify (G_OBJECT (user), "home-directory");
     456                g_signal_emit (user, signals[ICON_CHANGED], 0);
     457        }
     458
     459        /* Shell */
     460        if ((pwent->pw_shell && !user->shell) ||
     461            (!pwent->pw_shell && user->shell) ||
     462            (pwent->pw_shell &&
     463             user->shell &&
     464             strcmp (user->shell, pwent->pw_shell) != 0)) {
     465                g_free (user->shell);
     466                user->shell = g_strdup (pwent->pw_shell);
     467                g_object_notify (G_OBJECT (user), "shell");
     468        }
     469
     470        update_icon_monitor (user);
     471
     472        g_object_thaw_notify (G_OBJECT (user));
     473}
     474
     475/**
     476 * gdm_user_get_uid:
     477 * @user: the user object to examine.
     478 *
     479 * Retrieves the ID of @user.
     480 *
     481 * Returns: a pointer to an array of characters which must not be modified or
     482 *  freed, or %NULL.
     483 *
     484 * Since: 1.0
     485 **/
     486
     487uid_t
     488gdm_user_get_uid (GdmUser *user)
     489{
     490        g_return_val_if_fail (GDM_IS_USER (user), -1);
     491
     492        return user->uid;
     493}
     494
     495/**
     496 * gdm_user_get_real_name:
     497 * @user: the user object to examine.
     498 *
     499 * Retrieves the display name of @user.
     500 *
     501 * Returns: a pointer to an array of characters which must not be modified or
     502 *  freed, or %NULL.
     503 *
     504 * Since: 1.0
     505 **/
     506G_CONST_RETURN gchar *
     507gdm_user_get_real_name (GdmUser *user)
     508{
     509        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     510
     511        return (user->real_name ? user->real_name : user->user_name);
     512}
     513
     514/**
     515 * gdm_user_get_user_name:
     516 * @user: the user object to examine.
     517 *
     518 * Retrieves the login name of @user.
     519 *
     520 * Returns: a pointer to an array of characters which must not be modified or
     521 *  freed, or %NULL.
     522 *
     523 * Since: 1.0
     524 **/
     525
     526G_CONST_RETURN gchar *
     527gdm_user_get_user_name (GdmUser *user)
     528{
     529        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     530
     531        return user->user_name;
     532}
     533
     534/**
     535 * gdm_user_get_home_directory:
     536 * @user: the user object to examine.
     537 *
     538 * Retrieves the home directory of @user.
     539 *
     540 * Returns: a pointer to an array of characters which must not be modified or
     541 *  freed, or %NULL.
     542 *
     543 * Since: 1.0
     544 **/
     545
     546G_CONST_RETURN gchar *
     547gdm_user_get_home_directory (GdmUser *user)
     548{
     549        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     550
     551        return user->home_dir;
     552}
     553
     554/**
     555 * gdm_user_get_shell:
     556 * @user: the user object to examine.
     557 *
     558 * Retrieves the login shell of @user.
     559 *
     560 * Returns: a pointer to an array of characters which must not be modified or
     561 *  freed, or %NULL.
     562 *
     563 * Since: 1.0
     564 **/
     565
     566G_CONST_RETURN gchar *
     567gdm_user_get_shell (GdmUser *user)
     568{
     569        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     570
     571        return user->shell;
     572}
     573
     574gulong
     575gdm_user_get_login_frequency (GdmUser *user)
     576{
     577        g_return_val_if_fail (GDM_IS_USER (user), 0);
     578
     579        return user->login_frequency;
     580}
     581
     582G_CONST_RETURN gchar *
     583gdm_user_get_icon_url (GdmUser *user)
     584{
     585        g_return_val_if_fail (GDM_IS_USER (user), NULL);
     586
     587        /* FIXME: Icon can be one of:
     588         * ~/.face
     589         * ~/.face.icon
     590         * ~/.gnome/gdm:[face]picture
     591         * ${GlobalFaceDir}/${username}
     592         * ${GlobalFaceDir}/${username}.png
     593         * but we only monitor the first.
     594         */   
     595        return user->icon_url;
     596}
  • daemon/gdm-user.h

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/gdm-user.h gdm-2.28.0.new/daemon/gdm-user.h
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
     4 * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
     5 *
     6 * This program is free software; you can redistribute it and/or modify
     7 * it under the terms of the GNU General Public License as published by
     8 * the Free Software Foundation; either version 2 of the License, or
     9 * (at your option) any later version.
     10 *
     11 * This program is distributed in the hope that it will be useful,
     12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     14 * GNU General Public License for more details.
     15 *
     16 * You should have received a copy of the GNU General Public License
     17 * along with this program; if not, write to the Free Software
     18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     19 */
     20
     21/*
     22 * Facade object for user data, owned by GdmUserManager
     23 */
     24
     25#ifndef __GDM_USER__
     26#define __GDM_USER__ 1
     27
     28#include <sys/types.h>
     29#include <glib-object.h>
     30
     31G_BEGIN_DECLS
     32
     33#define GDM_TYPE_USER (gdm_user_get_type ())
     34#define GDM_USER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GDM_TYPE_USER, GdmUser))
     35#define GDM_IS_USER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GDM_TYPE_USER))
     36
     37typedef struct _GdmUser GdmUser;
     38
     39GType                  gdm_user_get_type            (void) G_GNUC_CONST;
     40
     41uid_t                  gdm_user_get_uid             (GdmUser   *user);
     42G_CONST_RETURN gchar  *gdm_user_get_user_name       (GdmUser   *user);
     43G_CONST_RETURN gchar  *gdm_user_get_real_name       (GdmUser   *user);
     44G_CONST_RETURN gchar  *gdm_user_get_home_directory  (GdmUser   *user);
     45G_CONST_RETURN gchar  *gdm_user_get_shell           (GdmUser   *user);
     46guint                  gdm_user_get_num_sessions    (GdmUser   *user);
     47GList                 *gdm_user_get_sessions        (GdmUser   *user);
     48gulong                 gdm_user_get_login_frequency (GdmUser   *user);
     49G_CONST_RETURN gchar  *gdm_user_get_icon_url        (GdmUser   *user);
     50
     51G_END_DECLS
     52
     53#endif
  • daemon/gdm-user-manager.c

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/gdm-user-manager.c gdm-2.28.0.new/daemon/gdm-user-manager.c
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2007-2008 William Jon McCann <mccann@jhu.edu>
     4 *
     5 * This program is free software; you can redistribute it and/or modify
     6 * it under the terms of the GNU General Public License as published by
     7 * the Free Software Foundation; either version 2 of the License, or
     8 * (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     18 *
     19 */
     20
     21#include "config.h"
     22
     23#include <stdlib.h>
     24#include <stdio.h>
     25#include <fcntl.h>
     26#include <unistd.h>
     27#include <string.h>
     28#include <signal.h>
     29#include <errno.h>
     30#include <sys/stat.h>
     31#include <sys/types.h>
     32
     33#ifdef HAVE_PATHS_H
     34#include <paths.h>
     35#endif /* HAVE_PATHS_H */
     36
     37#include <glib.h>
     38#include <glib/gi18n.h>
     39#include <glib/gstdio.h>
     40#include <glib-object.h>
     41#include <gio/gio.h>
     42
     43#include <dbus/dbus.h>
     44#include <dbus/dbus-glib.h>
     45#include <dbus/dbus-glib-lowlevel.h>
     46
     47#include "gdm-user-manager.h"
     48#include "gdm-user-manager-glue.h"
     49#include "gdm-user-private.h"
     50
     51#define GDM_USER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerPrivate))
     52
     53#define GDM_DBUS_PATH         "/org/gnome/DisplayManager"
     54#define GDM_USER_MANAGER_DBUS_PATH GDM_DBUS_PATH "/UserManager"
     55#define GDM_USER_MANAGER_DBUS_NAME "org.gnome.DisplayManager.UserManager"
     56
     57#define CK_NAME      "org.freedesktop.ConsoleKit"
     58#define CK_PATH      "/org/freedesktop/ConsoleKit"
     59#define CK_INTERFACE "org.freedesktop.ConsoleKit"
     60
     61#define CK_MANAGER_PATH      "/org/freedesktop/ConsoleKit/Manager"
     62#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager"
     63#define CK_SEAT_INTERFACE    "org.freedesktop.ConsoleKit.Seat"
     64#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session"
     65
     66#ifdef __sun
     67#define DEFAULT_MINIMAL_UID     100
     68#else
     69#define DEFAULT_MINIMAL_UID     500
     70#endif
     71
     72#ifndef _PATH_SHELLS
     73#define _PATH_SHELLS    "/etc/shells"
     74#endif
     75#define PATH_PASSWD     "/etc/passwd"
     76
     77#define LOGIN_CACHE_FILE CACHEDIR "/login_frequency.cache"
     78
     79#define DEFAULT_EXCLUDE         { "bin",        \
     80                                  "root",       \
     81                                  "daemon",     \
     82                                  "adm",        \
     83                                  "lp",         \
     84                                  "sync",       \
     85                                  "shutdown",   \
     86                                  "halt",       \
     87                                  "mail",       \
     88                                  "news",       \
     89                                  "uucp",       \
     90                                  "operator",   \
     91                                  "nobody",     \
     92                                  "nobody4",    \
     93                                  "noaccess",   \
     94                                  GDM_USERNAME, \
     95                                  "postgres",   \
     96                                  "pvm",        \
     97                                  "rpm",        \
     98                                  "nfsnobody",  \
     99                                  "pcap",       \
     100                                  NULL }
     101
     102struct GdmUserManagerPrivate
     103{
     104        GHashTable            *users;
     105        GHashTable            *sessions;
     106        GHashTable            *exclusions;
     107        GHashTable            *shells;
     108        DBusGConnection       *connection;
     109        DBusGProxy            *seat_proxy;
     110        char                  *seat_id;
     111
     112        GFileMonitor          *passwd_monitor;
     113        GFileMonitor          *shells_monitor;
     114
     115        guint                  reload_id;
     116        guint                  ck_history_id;
     117
     118        guint8                 loaded_passwd : 1;   
     119        guint8                 loaded_cache : 1;
     120};
     121
     122enum {
     123        USERS_LOADED,
     124        USER_ADDED,
     125        USER_REMOVED,
     126        USER_UPDATED,
     127        LAST_SIGNAL
     128};
     129
     130static guint signals [LAST_SIGNAL] = { 0, };
     131
     132static void     gdm_user_manager_class_init (GdmUserManagerClass *klass);
     133static void     gdm_user_manager_init       (GdmUserManager      *user_manager);
     134static void     gdm_user_manager_finalize   (GObject             *object);
     135
     136G_DEFINE_TYPE (GdmUserManager, gdm_user_manager, G_TYPE_OBJECT)
     137
     138GQuark
     139gdm_user_manager_error_quark (void)
     140{
     141        static GQuark ret = 0;
     142        if (ret == 0) {
     143                ret = g_quark_from_static_string ("gdm_user_manager_error");
     144        }
     145
     146        return ret;
     147}
     148
     149static void
     150on_user_sessions_changed (GdmUser        *user,
     151                          GdmUserManager *manager)
     152{
     153        guint nsessions;
     154
     155        nsessions = gdm_user_get_num_sessions (user);
     156
     157        g_debug ("GdmUserManager: sessions changed user=%s num=%d",
     158                 gdm_user_get_user_name (user),
     159                 nsessions);
     160
     161        /* only signal on zero and one */
     162        if (nsessions > 1) {
     163                return;
     164        }
     165
     166        g_signal_emit (manager, signals [USER_UPDATED], 0, gdm_user_get_uid (user));
     167}
     168
     169static void
     170on_user_icon_changed (GdmUser        *user,
     171                      GdmUserManager *manager)
     172{
     173        g_debug ("GdmUserManager: user icon changed");
     174}
     175
     176static char *
     177get_seat_id_for_session (DBusGConnection *connection,
     178                         const char      *session_id)
     179{
     180        DBusGProxy      *proxy;
     181        GError          *error;
     182        char            *seat_id;
     183        gboolean         res;
     184
     185        proxy = NULL;
     186        seat_id = NULL;
     187
     188        proxy = dbus_g_proxy_new_for_name (connection,
     189                                           CK_NAME,
     190                                           session_id,
     191                                           CK_SESSION_INTERFACE);
     192        if (proxy == NULL) {
     193                g_warning ("Failed to connect to the ConsoleKit session object");
     194                goto out;
     195        }
     196
     197        error = NULL;
     198        res = dbus_g_proxy_call (proxy,
     199                                 "GetSeatId",
     200                                 &error,
     201                                 G_TYPE_INVALID,
     202                                 DBUS_TYPE_G_OBJECT_PATH, &seat_id,
     203                                 G_TYPE_INVALID);
     204        if (! res) {
     205                if (error != NULL) {
     206                        g_debug ("Failed to identify the current seat: %s", error->message);
     207                        g_error_free (error);
     208                } else {
     209                        g_debug ("Failed to identify the current seat");
     210                }
     211        }
     212 out:
     213        if (proxy != NULL) {
     214                g_object_unref (proxy);
     215        }
     216
     217        return seat_id;
     218}
     219
     220static char *
     221get_x11_display_for_session (DBusGConnection *connection,
     222                             const char      *session_id)
     223{
     224        DBusGProxy      *proxy;
     225        GError          *error;
     226        char            *x11_display;
     227        gboolean         res;
     228
     229        proxy = NULL;
     230        x11_display = NULL;
     231
     232        proxy = dbus_g_proxy_new_for_name (connection,
     233                                           CK_NAME,
     234                                           session_id,
     235                                           CK_SESSION_INTERFACE);
     236        if (proxy == NULL) {
     237                g_warning ("Failed to connect to the ConsoleKit session object");
     238                goto out;
     239        }
     240
     241        error = NULL;
     242        res = dbus_g_proxy_call (proxy,
     243                                 "GetX11Display",
     244                                 &error,
     245                                 G_TYPE_INVALID,
     246                                 G_TYPE_STRING, &x11_display,
     247                                 G_TYPE_INVALID);
     248        if (! res) {
     249                if (error != NULL) {
     250                        g_debug ("Failed to identify the x11 display: %s", error->message);
     251                        g_error_free (error);
     252                } else {
     253                        g_debug ("Failed to identify the x11 display");
     254                }
     255        }
     256 out:
     257        if (proxy != NULL) {
     258                g_object_unref (proxy);
     259        }
     260
     261        return x11_display;
     262}
     263
     264static gboolean
     265maybe_add_session_for_user (GdmUserManager *manager,
     266                            GdmUser        *user,
     267                            const char     *ssid)
     268{
     269        char    *sid;
     270        char    *x11_display;
     271        gboolean ret;
     272
     273        ret = FALSE;
     274        sid = NULL;
     275        x11_display = NULL;
     276
     277        /* skip if on another seat */
     278        sid = get_seat_id_for_session (manager->priv->connection, ssid);
     279        if (sid == NULL
     280            || manager->priv->seat_id == NULL
     281            || strcmp (sid, manager->priv->seat_id) != 0) {
     282                g_debug ("GdmUserManager: not adding session on other seat: %s", ssid);
     283                goto out;
     284        }
     285
     286        /* skip if doesn't have an x11 display */
     287        x11_display = get_x11_display_for_session (manager->priv->connection, ssid);
     288        if (x11_display == NULL || x11_display[0] == '\0') {
     289                g_debug ("GdmUserManager: not adding session without a x11 display: %s", ssid);
     290                goto out;
     291        }
     292
     293        if (g_hash_table_lookup (manager->priv->exclusions, gdm_user_get_user_name (user))) {
     294                g_debug ("GdmUserManager: excluding user '%s'", gdm_user_get_user_name (user));
     295                goto out;
     296        }
     297
     298        g_hash_table_insert (manager->priv->sessions,
     299                             g_strdup (ssid),
     300                             g_strdup (gdm_user_get_user_name (user)));
     301
     302        _gdm_user_add_session (user, ssid);
     303        g_debug ("GdmUserManager: added session for user: %s", gdm_user_get_user_name (user));
     304
     305        ret = TRUE;
     306
     307 out:
     308        g_free (sid);
     309        g_free (x11_display);
     310
     311        return ret;
     312}
     313
     314static void
     315add_sessions_for_user (GdmUserManager *manager,
     316                       GdmUser        *user)
     317{
     318        DBusGProxy      *proxy;
     319        GError          *error;
     320        gboolean         res;
     321        guint32          uid;
     322        GPtrArray       *sessions;
     323        int              i;
     324
     325        proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
     326                                           CK_NAME,
     327                                           CK_MANAGER_PATH,
     328                                           CK_MANAGER_INTERFACE);
     329        if (proxy == NULL) {
     330                g_warning ("Failed to connect to the ConsoleKit manager object");
     331                goto out;
     332        }
     333
     334        uid = gdm_user_get_uid (user);
     335
     336        g_debug ("Getting list of sessions for user %u", uid);
     337
     338        error = NULL;
     339        res = dbus_g_proxy_call (proxy,
     340                                 "GetSessionsForUnixUser",
     341                                 &error,
     342                                 G_TYPE_UINT, uid,
     343                                 G_TYPE_INVALID,
     344                                 dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH),
     345                                 &sessions,
     346                                 G_TYPE_INVALID);
     347        if (! res) {
     348                if (error != NULL) {
     349                        g_debug ("Failed to find sessions for user: %s", error->message);
     350                        g_error_free (error);
     351                } else {
     352                        g_debug ("Failed to find sessions for user");
     353                }
     354                goto out;
     355        }
     356
     357        g_debug ("Found %d sessions for user %s", sessions->len, gdm_user_get_user_name (user));
     358
     359        for (i = 0; i < sessions->len; i++) {
     360                char *ssid;
     361
     362                ssid = g_ptr_array_index (sessions, i);
     363                maybe_add_session_for_user (manager, user, ssid);
     364        }
     365
     366        g_ptr_array_foreach (sessions, (GFunc)g_free, NULL);
     367        g_ptr_array_free (sessions, TRUE);
     368
     369 out:
     370        if (proxy != NULL) {
     371                g_object_unref (proxy);
     372        }
     373}
     374
     375static GdmUser *
     376create_user (GdmUserManager *manager)
     377{
     378        GdmUser *user;
     379
     380        user = g_object_new (GDM_TYPE_USER, NULL);
     381        g_signal_connect (user,
     382                          "sessions-changed",
     383                          G_CALLBACK (on_user_sessions_changed),
     384                          manager);
     385        g_signal_connect (user,
     386                          "icon-changed",
     387                          G_CALLBACK (on_user_icon_changed),
     388                          manager);
     389        return user;
     390}
     391
     392static void
     393add_user (GdmUserManager *manager,
     394          GdmUser        *user)
     395{
     396        add_sessions_for_user (manager, user);
     397        g_hash_table_insert (manager->priv->users,
     398                             g_strdup (gdm_user_get_user_name (user)),
     399                             g_object_ref (user));
     400
     401        g_signal_emit (manager, signals[USER_ADDED], 0, gdm_user_get_uid (user));
     402}
     403
     404static GdmUser *
     405add_new_user_for_pwent (GdmUserManager *manager,
     406                        struct passwd  *pwent)
     407{
     408        GdmUser *user;
     409
     410        g_debug ("Creating new user");
     411
     412        user = create_user (manager);
     413        _gdm_user_update (user, pwent);
     414
     415        add_user (manager, user);
     416
     417        return user;
     418}
     419
     420static char *
     421get_current_seat_id (DBusGConnection *connection)
     422{
     423        DBusGProxy      *proxy;
     424        GError          *error;
     425        char            *session_id;
     426        char            *seat_id;
     427        gboolean         res;
     428
     429        proxy = NULL;
     430        session_id = NULL;
     431        seat_id = NULL;
     432
     433        proxy = dbus_g_proxy_new_for_name (connection,
     434                                           CK_NAME,
     435                                           CK_MANAGER_PATH,
     436                                           CK_MANAGER_INTERFACE);
     437        if (proxy == NULL) {
     438                g_warning ("Failed to connect to the ConsoleKit manager object");
     439                goto out;
     440        }
     441
     442        error = NULL;
     443        res = dbus_g_proxy_call (proxy,
     444                                 "GetCurrentSession",
     445                                 &error,
     446                                 G_TYPE_INVALID,
     447                                 DBUS_TYPE_G_OBJECT_PATH,
     448                                 &session_id,
     449                                 G_TYPE_INVALID);
     450        if (! res) {
     451                if (error != NULL) {
     452                        g_debug ("Failed to identify the current session: %s", error->message);
     453                        g_error_free (error);
     454                } else {
     455                        g_debug ("Failed to identify the current session");
     456                }
     457                goto out;
     458        }
     459
     460        seat_id = get_seat_id_for_session (connection, session_id);
     461
     462 out:
     463        if (proxy != NULL) {
     464                g_object_unref (proxy);
     465        }
     466        g_free (session_id);
     467
     468        return seat_id;
     469}
     470
     471static gboolean
     472get_uid_from_session_id (GdmUserManager *manager,
     473                         const char     *session_id,
     474                         uid_t          *uidp)
     475{
     476        DBusGProxy      *proxy;
     477        GError          *error;
     478        guint            uid;
     479        gboolean         res;
     480
     481        proxy = dbus_g_proxy_new_for_name (manager->priv->connection,
     482                                           CK_NAME,
     483                                           session_id,
     484                                           CK_SESSION_INTERFACE);
     485        if (proxy == NULL) {
     486                g_warning ("Failed to connect to the ConsoleKit session object");
     487                return FALSE;
     488        }
     489
     490        error = NULL;
     491        res = dbus_g_proxy_call (proxy,
     492                                 "GetUnixUser",
     493                                 &error,
     494                                 G_TYPE_INVALID,
     495                                 G_TYPE_UINT, &uid,
     496                                 G_TYPE_INVALID);
     497        g_object_unref (proxy);
     498
     499        if (! res) {
     500                if (error != NULL) {
     501                        g_warning ("Failed to query the session: %s", error->message);
     502                        g_error_free (error);
     503                } else {
     504                        g_warning ("Failed to query the session");
     505                }
     506                return FALSE;
     507        }
     508
     509        if (uidp != NULL) {
     510                *uidp = (uid_t) uid;
     511        }
     512
     513        return TRUE;
     514}
     515
     516static void
     517seat_session_added (DBusGProxy     *seat_proxy,
     518                    const char     *session_id,
     519                    GdmUserManager *manager)
     520{
     521        uid_t          uid;
     522        gboolean       res;
     523        struct passwd *pwent;
     524        GdmUser       *user;
     525        gboolean       is_new;
     526
     527        g_debug ("Session added: %s", session_id);
     528
     529        res = get_uid_from_session_id (manager, session_id, &uid);
     530        if (! res) {
     531                g_warning ("Unable to lookup user for session");
     532                return;
     533        }
     534
     535        errno = 0;
     536        pwent = getpwuid (uid);
     537        if (pwent == NULL) {
     538                g_warning ("Unable to lookup user id %d: %s", (int)uid, g_strerror (errno));
     539                return;
     540        }
     541
     542        /* check exclusions up front */
     543        if (g_hash_table_lookup (manager->priv->exclusions, pwent->pw_name)) {
     544                g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name);
     545                return;
     546        }
     547
     548        user = g_hash_table_lookup (manager->priv->users, pwent->pw_name);
     549        if (user == NULL) {
     550                g_debug ("Creating new user");
     551
     552                user = create_user (manager);
     553                _gdm_user_update (user, pwent);
     554                is_new = TRUE;
     555        } else {
     556                is_new = FALSE;
     557        }
     558
     559        res = maybe_add_session_for_user (manager, user, session_id);
     560
     561        /* only add the user if we added a session */
     562        if (is_new) {
     563                if (res) {
     564                        add_user (manager, user);
     565                } else {
     566                        g_object_unref (user);
     567                }
     568        }
     569}
     570
     571static void
     572seat_session_removed (DBusGProxy     *seat_proxy,
     573                      const char     *session_id,
     574                      GdmUserManager *manager)
     575{
     576        GdmUser *user;
     577        char    *username;
     578
     579        g_debug ("Session removed: %s", session_id);
     580
     581        /* since the session object may already be gone
     582         * we can't query CK directly */
     583
     584        username = g_hash_table_lookup (manager->priv->sessions, session_id);
     585        if (username == NULL) {
     586                return;
     587        }
     588
     589        user = g_hash_table_lookup (manager->priv->users, username);
     590        if (user == NULL) {
     591                /* nothing to do */
     592                return;
     593        }
     594
     595        g_debug ("GdmUserManager: Session removed for %s", username);
     596        _gdm_user_remove_session (user, session_id);
     597}
     598
     599static void
     600on_proxy_destroy (DBusGProxy     *proxy,
     601                  GdmUserManager *manager)
     602{
     603        g_debug ("GdmUserManager: seat proxy destroyed");
     604
     605        manager->priv->seat_proxy = NULL;
     606}
     607
     608static void
     609get_seat_proxy (GdmUserManager *manager)
     610{
     611        DBusGProxy      *proxy;
     612        GError          *error;
     613
     614        g_assert (manager->priv->seat_proxy == NULL);
     615
     616        error = NULL;
     617        manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
     618        if (manager->priv->connection == NULL) {
     619                if (error != NULL) {
     620                        g_warning ("Failed to connect to the D-Bus daemon: %s", error->message);
     621                        g_error_free (error);
     622                } else {
     623                        g_warning ("Failed to connect to the D-Bus daemon");
     624                }
     625                return;
     626        }
     627
     628        manager->priv->seat_id = get_current_seat_id (manager->priv->connection);
     629        if (manager->priv->seat_id == NULL) {
     630                return;
     631        }
     632
     633        g_debug ("GdmUserManager: Found current seat: %s", manager->priv->seat_id);
     634
     635        error = NULL;
     636        proxy = dbus_g_proxy_new_for_name_owner (manager->priv->connection,
     637                                                 CK_NAME,
     638                                                 manager->priv->seat_id,
     639                                                 CK_SEAT_INTERFACE,
     640                                                 &error);
     641
     642        if (proxy == NULL) {
     643                if (error != NULL) {
     644                        g_warning ("Failed to connect to the ConsoleKit seat object: %s",
     645                                   error->message);
     646                        g_error_free (error);
     647                } else {
     648                        g_warning ("Failed to connect to the ConsoleKit seat object");
     649                }
     650                return;
     651        }
     652
     653        g_signal_connect (proxy, "destroy", G_CALLBACK (on_proxy_destroy), manager);
     654
     655        dbus_g_proxy_add_signal (proxy,
     656                                 "SessionAdded",
     657                                 DBUS_TYPE_G_OBJECT_PATH,
     658                                 G_TYPE_INVALID);
     659        dbus_g_proxy_add_signal (proxy,
     660                                 "SessionRemoved",
     661                                 DBUS_TYPE_G_OBJECT_PATH,
     662                                 G_TYPE_INVALID);
     663        dbus_g_proxy_connect_signal (proxy,
     664                                     "SessionAdded",
     665                                     G_CALLBACK (seat_session_added),
     666                                     manager,
     667                                     NULL);
     668        dbus_g_proxy_connect_signal (proxy,
     669                                     "SessionRemoved",
     670                                     G_CALLBACK (seat_session_removed),
     671                                     manager,
     672                                     NULL);
     673        manager->priv->seat_proxy = proxy;
     674
     675}
     676
     677/**
     678 * gdm_manager_get_user:
     679 * @manager: the manager to query.
     680 * @username: the login name of the user to get.
     681 *
     682 * Retrieves a pointer to the #GdmUser object for the login named @username
     683 * from @manager. This pointer is not a reference, and should not be released.
     684 *
     685 * Returns: a pointer to a #GdmUser object.
     686 **/
     687static GdmUser *
     688gdm_user_manager_get_user (GdmUserManager *manager,
     689                           const char     *username)
     690{
     691        GdmUser *user;
     692
     693        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL);
     694        g_return_val_if_fail (username != NULL && username[0] != '\0', NULL);
     695
     696        user = g_hash_table_lookup (manager->priv->users, username);
     697
     698        if (user == NULL) {
     699                struct passwd *pwent;
     700
     701                pwent = getpwnam (username);
     702
     703                if (pwent != NULL) {
     704                        user = add_new_user_for_pwent (manager, pwent);
     705                }
     706        }
     707
     708        return user;
     709}
     710
     711static GdmUser *
     712gdm_user_manager_get_user_by_uid (GdmUserManager *manager,
     713                                  uid_t           uid)
     714{
     715        GdmUser       *user;
     716        struct passwd *pwent;
     717
     718        g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL);
     719
     720        pwent = getpwuid (uid);
     721        if (pwent == NULL) {
     722                g_warning ("GdmUserManager: unable to lookup uid %d", (int)uid);
     723                return NULL;
     724        }
     725
     726        user = g_hash_table_lookup (manager->priv->users, pwent->pw_name);
     727
     728        if (user == NULL) {
     729                user = add_new_user_for_pwent (manager, pwent);
     730        }
     731
     732        return user;
     733}
     734
     735static void
     736listify_hash_values_hfunc (gpointer key,
     737                           gpointer value,
     738                           gpointer user_data)
     739{
     740        GSList **list = user_data;
     741
     742        *list = g_slist_prepend (*list, value);
     743}
     744
     745static gboolean
     746parse_value_as_ulong (const char *value,
     747                      gulong     *ulongval)
     748{
     749        char  *end_of_valid_long;
     750        glong  long_value;
     751        gulong ulong_value;
     752
     753        errno = 0;
     754        long_value = strtol (value, &end_of_valid_long, 10);
     755
     756        if (*value == '\0' || *end_of_valid_long != '\0') {
     757                return FALSE;
     758        }
     759
     760        ulong_value = long_value;
     761        if (ulong_value != long_value || errno == ERANGE) {
     762                return FALSE;
     763        }
     764
     765        *ulongval = ulong_value;
     766
     767        return TRUE;
     768}
     769
     770static gboolean
     771parse_ck_history_line (const char *line,
     772                       char      **user_namep,
     773                       gulong     *frequencyp)
     774{
     775        GRegex     *re;
     776        GMatchInfo *match_info;
     777        gboolean    res;
     778        gboolean    ret;
     779        GError     *error;
     780
     781        ret = FALSE;
     782        re = NULL;
     783        match_info = NULL;
     784
     785        error = NULL;
     786        re = g_regex_new ("(?P<username>[0-9a-zA-Z]+)[ ]+(?P<frequency>[0-9]+)", 0, 0, &error);
     787        if (re == NULL) {
     788                if (error != NULL) {
     789                        g_critical ("%s", error->message);
     790                } else {
     791                        g_critical ("Error in regex call");
     792                }
     793                goto out;
     794        }
     795
     796        g_regex_match (re, line, 0, &match_info);
     797
     798        res = g_match_info_matches (match_info);
     799        if (! res) {
     800                g_warning ("Unable to parse history: %s", line);
     801                goto out;
     802        }
     803
     804        if (user_namep != NULL) {
     805                *user_namep = g_match_info_fetch_named (match_info, "username");
     806        }
     807
     808        if (frequencyp != NULL) {
     809                char *freq;
     810                freq = g_match_info_fetch_named (match_info, "frequency");
     811                res = parse_value_as_ulong (freq, frequencyp);
     812                g_free (freq);
     813                if (! res) {
     814                        goto out;
     815                }
     816        }
     817
     818        ret = TRUE;
     819
     820 out:
     821        if (match_info != NULL) {
     822                g_match_info_free (match_info);
     823        }
     824        if (re != NULL) {
     825                g_regex_unref (re);
     826        }
     827        return ret;
     828}
     829
     830static void
     831process_ck_history_line (GdmUserManager *manager,
     832                         const char     *line)
     833{
     834        gboolean res;
     835        char    *username;
     836        gulong   frequency;
     837        struct passwd *pwent;
     838        GdmUser *user;
     839
     840        frequency = 0;
     841        username = NULL;
     842        res = parse_ck_history_line (line, &username, &frequency);
     843        if (! res) {
     844                return;
     845        }
     846
     847        if (g_hash_table_lookup (manager->priv->exclusions, username)) {
     848                g_debug ("GdmUserManager: excluding user '%s'", username);
     849                g_free (username);
     850                return;
     851        }
     852
     853        /* do not show system users; we cannot use gdm_user_manager_get_user()
     854         * here since this creates/signals users as a side effect */
     855        pwent = getpwnam (username);
     856        if (pwent == NULL) {
     857                g_warning ("Unable to lookup user name %s: %s", username, g_strerror (errno));
     858                return;
     859        }
     860        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
     861                g_debug ("GdmUserManager: excluding user '%s'", username);
     862                return;
     863        }
     864
     865        user = gdm_user_manager_get_user (manager, username);
     866        if (user == NULL) {
     867                g_debug ("GdmUserManager: unable to lookup user '%s'", username);
     868                g_free (username);
     869                return;
     870        }
     871
     872        g_object_set (user, "login-frequency", frequency, NULL);
     873        g_signal_emit (manager, signals [USER_UPDATED], 0, gdm_user_get_uid (user));
     874        g_free (username);
     875}
     876
     877static gboolean
     878ck_history_watch (GIOChannel     *source,
     879                  GIOCondition    condition,
     880                  GdmUserManager *manager)
     881{
     882        GIOStatus status;
     883        gboolean  done  = FALSE;
     884
     885        g_return_val_if_fail (manager != NULL, FALSE);
     886
     887        if (condition & G_IO_IN) {
     888                char   *str;
     889                GError *error;
     890
     891                error = NULL;
     892                status = g_io_channel_read_line (source, &str, NULL, NULL, &error);
     893                if (error != NULL) {
     894                        g_warning ("GdmUserManager: unable to read line: %s", error->message);
     895                        g_error_free (error);
     896                }
     897
     898                if (status == G_IO_STATUS_NORMAL) {
     899                        g_debug ("GdmUserManager: history output: %s", str);
     900                        process_ck_history_line (manager, str);
     901                } else if (status == G_IO_STATUS_EOF) {
     902                        done = TRUE;
     903                }
     904
     905                g_free (str);
     906        } else if (condition & G_IO_HUP) {
     907                done = TRUE;
     908        }
     909
     910        if (done) {
     911                FILE *fp;
     912
     913                /* Cache login counts */
     914                fp = fopen (LOGIN_CACHE_FILE, "w");
     915                if (fp != NULL) {
     916                        GHashTableIter iter;
     917                        gpointer value;
     918
     919                        g_hash_table_iter_init (&iter, manager->priv->users);
     920                        while (g_hash_table_iter_next (&iter, NULL, &value)) {
     921                                GdmUser *user = (GdmUser *) value;
     922                                fprintf (fp, "%s %lu\n",
     923                                         gdm_user_get_user_name (user),
     924                                         gdm_user_get_login_frequency (user));
     925                        }
     926                        fclose (fp);
     927                }
     928                else
     929                        g_warning ("Unable to write to login cache file: %s", LOGIN_CACHE_FILE);
     930
     931                manager->priv->ck_history_id = 0;
     932                return FALSE;
     933        }
     934
     935        return TRUE;
     936}
     937
     938static void
     939reload_ck_history (GdmUserManager *manager)
     940{
     941        char       *command;
     942        const char *seat_id;
     943        GError     *error;
     944        gboolean    res;
     945        char      **argv;
     946        int         standard_out;
     947        GIOChannel *channel;
     948
     949        seat_id = NULL;
     950        if (manager->priv->seat_id != NULL
     951            && g_str_has_prefix (manager->priv->seat_id, "/org/freedesktop/ConsoleKit/")) {
     952
     953                seat_id = manager->priv->seat_id + strlen ("/org/freedesktop/ConsoleKit/");
     954        }
     955
     956        if (seat_id == NULL) {
     957                g_warning ("Unable to find users: no seat-id found");
     958                return;
     959        }
     960
     961        command = g_strdup_printf ("ck-history --frequent --seat='%s' --session-type=''",
     962                                   seat_id);
     963        g_debug ("GdmUserManager: running '%s'", command);
     964        error = NULL;
     965        if (! g_shell_parse_argv (command, NULL, &argv, &error)) {
     966                if (error != NULL) {
     967                        g_warning ("Could not parse command: %s", error->message);
     968                        g_error_free (error);
     969                } else {
     970                        g_warning ("Could not parse command");
     971                }
     972                goto out;
     973        }
     974
     975        error = NULL;
     976        res = g_spawn_async_with_pipes (NULL,
     977                                        argv,
     978                                        NULL,
     979                                        G_SPAWN_SEARCH_PATH,
     980                                        NULL,
     981                                        NULL,
     982                                        NULL, /* pid */
     983                                        NULL,
     984                                        &standard_out,
     985                                        NULL,
     986                                        &error);
     987        g_strfreev (argv);
     988        if (! res) {
     989                if (error != NULL) {
     990                        g_warning ("Unable to run ck-history: %s", error->message);
     991                        g_error_free (error);
     992                } else {
     993                        g_warning ("Unable to run ck-history");
     994                }
     995                goto out;
     996        }
     997
     998        channel = g_io_channel_unix_new (standard_out);
     999        g_io_channel_set_close_on_unref (channel, TRUE);
     1000        g_io_channel_set_flags (channel,
     1001                                g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK,
     1002                                NULL);
     1003        manager->priv->ck_history_id = g_io_add_watch (channel,
     1004                                                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
     1005                                                       (GIOFunc)ck_history_watch,
     1006                                                       manager);
     1007        g_io_channel_unref (channel);
     1008
     1009 out:
     1010        g_free (command);
     1011}
     1012
     1013static void
     1014reload_passwd (GdmUserManager *manager)
     1015{
     1016        struct passwd *pwent;
     1017        GSList        *old_users;
     1018        GSList        *new_users;
     1019        GSList        *list;
     1020        FILE          *fp;
     1021
     1022        old_users = NULL;
     1023        new_users = NULL;
     1024
     1025        errno = 0;
     1026        fp = fopen (PATH_PASSWD, "r");
     1027        if (fp == NULL) {
     1028                g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
     1029                goto out;
     1030        }
     1031
     1032        g_hash_table_foreach (manager->priv->users, listify_hash_values_hfunc, &old_users);
     1033        g_slist_foreach (old_users, (GFunc) g_object_ref, NULL);
     1034
     1035        /* Make sure we keep users who are logged in no matter what. */
     1036        for (list = old_users; list; list = list->next) {
     1037                if (gdm_user_get_num_sessions (list->data) > 0) {
     1038                        g_object_freeze_notify (G_OBJECT (list->data));
     1039                        new_users = g_slist_prepend (new_users, g_object_ref (list->data));
     1040                }
     1041        }
     1042
     1043        for (pwent = fgetpwent (fp); pwent != NULL; pwent = fgetpwent (fp)) {
     1044                GdmUser *user;
     1045
     1046                user = NULL;
     1047
     1048                /* Skip users below MinimalUID... */
     1049                if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
     1050                        continue;
     1051                }
     1052
     1053                /* ...And users w/ invalid shells... */
     1054                if (pwent->pw_shell == NULL ||
     1055                    !g_hash_table_lookup (manager->priv->shells, pwent->pw_shell)) {
     1056                        g_debug ("GdmUserManager: skipping user with bad shell: %s", pwent->pw_name);
     1057                        continue;
     1058                }
     1059
     1060                /* ...And explicitly excluded users */
     1061                if (g_hash_table_lookup (manager->priv->exclusions, pwent->pw_name)) {
     1062                        g_debug ("GdmUserManager: explicitly skipping user: %s", pwent->pw_name);
     1063                        continue;
     1064                }
     1065
     1066                user = g_hash_table_lookup (manager->priv->users, pwent->pw_name);
     1067
     1068                /* Update users already in the *new* list */
     1069                if (g_slist_find (new_users, user)) {
     1070                        _gdm_user_update (user, pwent);
     1071                        continue;
     1072                }
     1073
     1074                if (user == NULL) {
     1075                        user = create_user (manager);
     1076                } else {
     1077                        g_object_ref (user);
     1078                }
     1079
     1080                /* Freeze & update users not already in the new list */
     1081                g_object_freeze_notify (G_OBJECT (user));
     1082                _gdm_user_update (user, pwent);
     1083
     1084                new_users = g_slist_prepend (new_users, user);
     1085        }
     1086
     1087        /* Go through and handle removed users */
     1088        for (list = old_users; list; list = list->next) {
     1089                if (! g_slist_find (new_users, list->data)) {
     1090                        g_signal_emit (manager, signals[USER_REMOVED], 0, gdm_user_get_uid (GDM_USER (list->data)));
     1091                        g_hash_table_remove (manager->priv->users,
     1092                                             gdm_user_get_user_name (list->data));
     1093                }
     1094        }
     1095
     1096        /* Go through and handle added users */
     1097        for (list = new_users; list; list = list->next) {
     1098                if (!g_slist_find (old_users, list->data)) {
     1099                        add_user (manager, list->data);
     1100                }
     1101        }
     1102
     1103        if (!manager->priv->loaded_passwd) {
     1104                g_signal_emit (manager, signals[USERS_LOADED], 0);
     1105                manager->priv->loaded_passwd = TRUE;
     1106        }
     1107
     1108 out:
     1109        /* Cleanup */
     1110
     1111        fclose (fp);
     1112
     1113        g_slist_foreach (new_users, (GFunc) g_object_thaw_notify, NULL);
     1114        g_slist_foreach (new_users, (GFunc) g_object_unref, NULL);
     1115        g_slist_free (new_users);
     1116
     1117        g_slist_foreach (old_users, (GFunc) g_object_unref, NULL);
     1118        g_slist_free (old_users);
     1119}
     1120
     1121static void
     1122load_login_frequency_cache (GdmUserManager *manager)
     1123{
     1124        GIOChannel *channel;
     1125        gchar *line;
     1126
     1127        channel = g_io_channel_new_file (LOGIN_CACHE_FILE, "r", NULL);
     1128        if (channel == NULL)
     1129                return;
     1130
     1131        while (g_io_channel_read_line (channel, &line, NULL, NULL, NULL) == G_IO_STATUS_NORMAL) {
     1132                process_ck_history_line (manager, line);
     1133                g_free (line);
     1134        }
     1135   
     1136        g_io_channel_close (channel);
     1137}
     1138
     1139static void
     1140reload_users (GdmUserManager *manager)
     1141{
     1142        reload_passwd (manager);
     1143        if (!manager->priv->loaded_cache) {
     1144                load_login_frequency_cache (manager);
     1145                manager->priv->loaded_cache = TRUE;
     1146        }
     1147        reload_ck_history (manager);
     1148}
     1149
     1150static gboolean
     1151reload_users_timeout (GdmUserManager *manager)
     1152{
     1153        reload_users (manager);
     1154        manager->priv->reload_id = 0;
     1155
     1156        return FALSE;
     1157}
     1158
     1159static void
     1160queue_reload_users (GdmUserManager *manager)
     1161{
     1162        if (manager->priv->reload_id > 0) {
     1163                return;
     1164        }
     1165
     1166        manager->priv->reload_id = g_idle_add ((GSourceFunc)reload_users_timeout, manager);
     1167}
     1168
     1169static void
     1170reload_shells (GdmUserManager *manager)
     1171{
     1172        char *shell;
     1173
     1174        setusershell ();
     1175
     1176        g_hash_table_remove_all (manager->priv->shells);
     1177        for (shell = getusershell (); shell != NULL; shell = getusershell ()) {
     1178                /* skip well known not-real shells */
     1179                if (shell == NULL
     1180                    || strcmp (shell, "/sbin/nologin") == 0
     1181                    || strcmp (shell, "/bin/false") == 0) {
     1182                        g_debug ("GdmUserManager: skipping shell %s", shell);
     1183                        continue;
     1184                }
     1185                g_hash_table_insert (manager->priv->shells,
     1186                                     g_strdup (shell),
     1187                                     GUINT_TO_POINTER (TRUE));
     1188        }
     1189
     1190        endusershell ();
     1191}
     1192
     1193static void
     1194on_shells_monitor_changed (GFileMonitor     *monitor,
     1195                           GFile            *file,
     1196                           GFile            *other_file,
     1197                           GFileMonitorEvent event_type,
     1198                           GdmUserManager   *manager)
     1199{
     1200        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
     1201            event_type != G_FILE_MONITOR_EVENT_CREATED) {
     1202                return;
     1203        }
     1204
     1205        reload_shells (manager);
     1206        reload_passwd (manager);
     1207}
     1208
     1209static void
     1210on_passwd_monitor_changed (GFileMonitor     *monitor,
     1211                           GFile            *file,
     1212                           GFile            *other_file,
     1213                           GFileMonitorEvent event_type,
     1214                           GdmUserManager   *manager)
     1215{
     1216        if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
     1217            event_type != G_FILE_MONITOR_EVENT_CREATED) {
     1218                return;
     1219        }
     1220
     1221        reload_passwd (manager);
     1222}
     1223
     1224static void
     1225gdm_user_manager_class_init (GdmUserManagerClass *klass)
     1226{
     1227        GObjectClass   *object_class = G_OBJECT_CLASS (klass);
     1228
     1229        object_class->finalize = gdm_user_manager_finalize;
     1230
     1231        signals [USERS_LOADED] =
     1232                g_signal_new ("users-loaded",
     1233                              G_TYPE_FROM_CLASS (klass),
     1234                              G_SIGNAL_RUN_LAST,
     1235                              G_STRUCT_OFFSET (GdmUserManagerClass, users_loaded),
     1236                              NULL, NULL,
     1237                              g_cclosure_marshal_VOID__OBJECT,
     1238                              G_TYPE_NONE, 0);
     1239        signals [USER_ADDED] =
     1240                g_signal_new ("user-added",
     1241                              G_TYPE_FROM_CLASS (klass),
     1242                              G_SIGNAL_RUN_LAST,
     1243                              G_STRUCT_OFFSET (GdmUserManagerClass, user_added),
     1244                              NULL, NULL,
     1245                              g_cclosure_marshal_VOID__OBJECT,
     1246                              G_TYPE_NONE, 1, G_TYPE_INT64);
     1247        signals [USER_REMOVED] =
     1248                g_signal_new ("user-removed",
     1249                              G_TYPE_FROM_CLASS (klass),
     1250                              G_SIGNAL_RUN_LAST,
     1251                              G_STRUCT_OFFSET (GdmUserManagerClass, user_removed),
     1252                              NULL, NULL,
     1253                              g_cclosure_marshal_VOID__OBJECT,
     1254                              G_TYPE_NONE, 1, G_TYPE_INT64);
     1255        signals [USER_UPDATED] =
     1256                g_signal_new ("user-updated",
     1257                              G_TYPE_FROM_CLASS (klass),
     1258                              G_SIGNAL_RUN_LAST,
     1259                              G_STRUCT_OFFSET (GdmUserManagerClass, user_updated),
     1260                              NULL, NULL,
     1261                              g_cclosure_marshal_VOID__OBJECT,
     1262                              G_TYPE_NONE, 1, G_TYPE_INT64);
     1263
     1264        g_type_class_add_private (klass, sizeof (GdmUserManagerPrivate));
     1265
     1266        dbus_g_object_type_install_info (GDM_TYPE_USER_MANAGER, &dbus_glib_gdm_user_manager_object_info);
     1267}
     1268
     1269static void
     1270gdm_user_manager_init (GdmUserManager *manager)
     1271{
     1272        int            i;
     1273        GFile         *file;
     1274        GError        *error;
     1275        const char    *exclude_default[] = DEFAULT_EXCLUDE;
     1276
     1277        manager->priv = GDM_USER_MANAGER_GET_PRIVATE (manager);
     1278
     1279        /* sessions */
     1280        manager->priv->sessions = g_hash_table_new_full (g_str_hash,
     1281                                                         g_str_equal,
     1282                                                         g_free,
     1283                                                         g_free);
     1284
     1285        /* exclusions */
     1286        manager->priv->exclusions = g_hash_table_new_full (g_str_hash,
     1287                                                           g_str_equal,
     1288                                                           g_free,
     1289                                                           NULL);
     1290        for (i = 0; exclude_default[i] != NULL; i++) {
     1291                g_hash_table_insert (manager->priv->exclusions,
     1292                                     g_strdup (exclude_default [i]),
     1293                                     GUINT_TO_POINTER (TRUE));
     1294        }
     1295
     1296        /* /etc/shells */
     1297        manager->priv->shells = g_hash_table_new_full (g_str_hash,
     1298                                                       g_str_equal,
     1299                                                       g_free,
     1300                                                       NULL);
     1301        reload_shells (manager);
     1302        file = g_file_new_for_path (_PATH_SHELLS);
     1303        error = NULL;
     1304        manager->priv->shells_monitor = g_file_monitor_file (file,
     1305                                                             G_FILE_MONITOR_NONE,
     1306                                                             NULL,
     1307                                                             &error);
     1308        if (manager->priv->shells_monitor != NULL) {
     1309                g_signal_connect (manager->priv->shells_monitor,
     1310                                  "changed",
     1311                                  G_CALLBACK (on_shells_monitor_changed),
     1312                                  manager);
     1313        } else {
     1314                g_warning ("Unable to monitor %s: %s", _PATH_SHELLS, error->message);
     1315                g_error_free (error);
     1316        }
     1317        g_object_unref (file);
     1318
     1319        /* /etc/passwd */
     1320        manager->priv->users = g_hash_table_new_full (g_str_hash,
     1321                                                      g_str_equal,
     1322                                                      g_free,
     1323                                                      (GDestroyNotify) g_object_run_dispose);
     1324        file = g_file_new_for_path (PATH_PASSWD);
     1325        manager->priv->passwd_monitor = g_file_monitor_file (file,
     1326                                                             G_FILE_MONITOR_NONE,
     1327                                                             NULL,
     1328                                                             &error);
     1329        if (manager->priv->passwd_monitor != NULL) {
     1330                g_signal_connect (manager->priv->passwd_monitor,
     1331                                  "changed",
     1332                                  G_CALLBACK (on_passwd_monitor_changed),
     1333                                  manager);
     1334        } else {
     1335                g_warning ("Unable to monitor %s: %s", PATH_PASSWD, error->message);
     1336                g_error_free (error);
     1337        }
     1338        g_object_unref (file);
     1339
     1340
     1341        get_seat_proxy (manager);
     1342
     1343        queue_reload_users (manager);
     1344
     1345        dbus_g_connection_register_g_object (manager->priv->connection, GDM_USER_MANAGER_DBUS_PATH, G_OBJECT (manager));
     1346}
     1347
     1348static void
     1349gdm_user_manager_finalize (GObject *object)
     1350{
     1351        GdmUserManager *manager;
     1352
     1353        g_return_if_fail (object != NULL);
     1354        g_return_if_fail (GDM_IS_USER_MANAGER (object));
     1355
     1356        manager = GDM_USER_MANAGER (object);
     1357
     1358        g_return_if_fail (manager->priv != NULL);
     1359
     1360        if (manager->priv->seat_proxy != NULL) {
     1361                g_object_unref (manager->priv->seat_proxy);
     1362        }
     1363
     1364        if (manager->priv->ck_history_id != 0) {
     1365                g_source_remove (manager->priv->ck_history_id);
     1366                manager->priv->ck_history_id = 0;
     1367        }
     1368
     1369        if (manager->priv->reload_id > 0) {
     1370                g_source_remove (manager->priv->reload_id);
     1371                manager->priv->reload_id = 0;
     1372        }
     1373
     1374        g_hash_table_destroy (manager->priv->sessions);
     1375
     1376        g_file_monitor_cancel (manager->priv->passwd_monitor);
     1377        g_hash_table_destroy (manager->priv->users);
     1378
     1379        g_file_monitor_cancel (manager->priv->shells_monitor);
     1380        g_hash_table_destroy (manager->priv->shells);
     1381
     1382        g_free (manager->priv->seat_id);
     1383
     1384        G_OBJECT_CLASS (gdm_user_manager_parent_class)->finalize (object);
     1385}
     1386
     1387GdmUserManager *
     1388gdm_user_manager_new (void)
     1389{
     1390        return GDM_USER_MANAGER (g_object_new (GDM_TYPE_USER_MANAGER, NULL));
     1391}
     1392
     1393/*
     1394  Example:
     1395  dbus-send --system --print-reply --dest=org.gnome.DisplayManager \
     1396  /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.CountUsers
     1397*/
     1398gboolean
     1399gdm_user_manager_count_users (GdmUserManager *user_manager,
     1400                              gint           *user_count,
     1401                              GError        **error)
     1402{
     1403        *user_count = g_hash_table_size (user_manager->priv->users);
     1404   
     1405        return TRUE;
     1406}
     1407
     1408/*
     1409  Example:
     1410  dbus-send --system --print-reply --dest=org.gnome.DisplayManager \
     1411  /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUserList
     1412*/
     1413gboolean
     1414gdm_user_manager_get_user_list (GdmUserManager *user_manager,
     1415                                GArray        **user_list,
     1416                                GError        **error)
     1417{
     1418        GHashTableIter iter;
     1419        GdmUser *user;
     1420
     1421        *user_list = g_array_new (FALSE, FALSE, sizeof (gint64));
     1422        g_hash_table_iter_init (&iter, user_manager->priv->users);
     1423        while (g_hash_table_iter_next (&iter, NULL, (gpointer *)&user)) {
     1424                gint64 uid = gdm_user_get_uid (user);
     1425                g_array_append_val (*user_list, uid);
     1426        }
     1427
     1428        return TRUE;
     1429}
     1430
     1431
     1432/*
     1433  Example:
     1434  dbus-send --system --print-reply --dest=org.gnome.DisplayManager \
     1435  /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUserInfo int64:1000
     1436*/
     1437gboolean
     1438gdm_user_manager_get_user_info (GdmUserManager *user_manager,
     1439                                gint64          uid,
     1440                                gchar         **user_name,
     1441                                gchar         **real_name,
     1442                                gchar         **shell,
     1443                                gint           *login_count,
     1444                                gchar         **icon_url,
     1445                                GError        **error)
     1446{
     1447        GdmUser *user;
     1448
     1449        user = gdm_user_manager_get_user_by_uid (user_manager, uid);
     1450        if (user == NULL)
     1451                return FALSE;
     1452
     1453        *user_name = g_strdup (gdm_user_get_user_name (user));
     1454        *real_name = g_strdup (gdm_user_get_real_name (user));
     1455        *login_count = gdm_user_get_login_frequency (user);
     1456        *shell = g_strdup (gdm_user_get_shell (user));
     1457        *icon_url = g_strdup (gdm_user_get_icon_url (user));
     1458
     1459        return TRUE;
     1460}
     1461
     1462/*
     1463  Example:
     1464  dbus-send --system --print-reply --dest=org.gnome.DisplayManager \
     1465  /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUsersInfo array:int64:1000,1001
     1466*/
     1467gboolean
     1468gdm_user_manager_get_users_info (GdmUserManager *user_manager,
     1469                                 GArray         *uids,
     1470                                 GPtrArray     **users_info,
     1471                                 GError        **error)
     1472{
     1473        int i;
     1474   
     1475        *users_info = g_ptr_array_new ();
     1476
     1477        for (i = 0; i < uids->len; i++) {
     1478                gint64 uid;
     1479                GdmUser *user;
     1480                GValueArray *user_info;
     1481                GValue arg = {0};
     1482
     1483                uid = g_array_index (uids, gint64, i);
     1484                user = gdm_user_manager_get_user_by_uid (user_manager, uid);
     1485                if (user == NULL)
     1486                        continue;
     1487
     1488                user_info = g_value_array_new (5);
     1489
     1490                g_value_init (&arg, G_TYPE_INT64);
     1491                g_value_set_int64 (&arg, uid);
     1492                g_value_array_append (user_info, &arg);
     1493                g_value_unset (&arg);
     1494
     1495                g_value_init (&arg, G_TYPE_STRING);
     1496                g_value_set_string (&arg, gdm_user_get_user_name (user));
     1497                g_value_array_append (user_info, &arg);
     1498                g_value_unset (&arg);
     1499
     1500                g_value_init (&arg, G_TYPE_STRING);
     1501                g_value_set_string (&arg, gdm_user_get_real_name (user));
     1502                g_value_array_append (user_info, &arg);
     1503                g_value_unset (&arg);
     1504
     1505                g_value_init (&arg, G_TYPE_STRING);
     1506                g_value_set_string (&arg, gdm_user_get_shell (user));
     1507                g_value_array_append (user_info, &arg);
     1508                g_value_unset (&arg);
     1509
     1510                g_value_init (&arg, G_TYPE_INT);
     1511                g_value_set_int (&arg, gdm_user_get_login_frequency (user));
     1512                g_value_array_append (user_info, &arg);
     1513                g_value_unset (&arg);
     1514
     1515                g_value_init (&arg, G_TYPE_STRING);
     1516                g_value_set_string (&arg, gdm_user_get_icon_url (user));
     1517                g_value_array_append (user_info, &arg);
     1518                g_value_unset (&arg);
     1519
     1520                g_ptr_array_add (*users_info, user_info);
     1521        }
     1522   
     1523        return TRUE;
     1524}
     1525
     1526/*
     1527  Example:
     1528  dbus-send --system --print-reply --dest=org.gnome.DisplayManager \
     1529  /org/gnome/DisplayManager/UserManager org.gnome.DisplayManager.UserManager.GetUsersLoaded
     1530*/
     1531gboolean
     1532gdm_user_manager_get_users_loaded (GdmUserManager *user_manager,
     1533                                   gboolean       *is_loaded,
     1534                                   GError        **error)
     1535{
     1536        *is_loaded = user_manager->priv->loaded_passwd;
     1537        return TRUE;
     1538}
  • daemon/gdm-user-manager.h

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/gdm-user-manager.h gdm-2.28.0.new/daemon/gdm-user-manager.h
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
     4 *
     5 * This program is free software; you can redistribute it and/or modify
     6 * it under the terms of the GNU General Public License as published by
     7 * the Free Software Foundation; either version 2 of the License, or
     8 * (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     18 *
     19 */
     20
     21#ifndef __GDM_USER_MANAGER_H
     22#define __GDM_USER_MANAGER_H
     23
     24#include <glib-object.h>
     25
     26#include "gdm-user.h"
     27
     28G_BEGIN_DECLS
     29
     30#define GDM_TYPE_USER_MANAGER         (gdm_user_manager_get_type ())
     31#define GDM_USER_MANAGER(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_MANAGER, GdmUserManager))
     32#define GDM_USER_MANAGER_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_MANAGER, GdmUserManagerClass))
     33#define GDM_IS_USER_MANAGER(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_MANAGER))
     34#define GDM_IS_USER_MANAGER_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_MANAGER))
     35#define GDM_USER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerClass))
     36
     37typedef struct GdmUserManagerPrivate GdmUserManagerPrivate;
     38
     39typedef struct
     40{
     41        GObject                parent;
     42        GdmUserManagerPrivate *priv;
     43} GdmUserManager;
     44
     45typedef struct
     46{
     47        GObjectClass   parent_class;
     48
     49        void          (* users_loaded)              (GdmUserManager *user_manager);
     50        void          (* user_added)                (GdmUserManager *user_manager,
     51                                                     gint64          uid);
     52        void          (* user_removed)              (GdmUserManager *user_manager,
     53                                                     gint64          uid);
     54        void          (* user_updated)              (GdmUserManager *user_manager,
     55                                                     gint64          uid);
     56} GdmUserManagerClass;
     57
     58#define GDM_USER_MANAGER_ERROR gdm_user_manager_error_quark ()
     59
     60GQuark              gdm_user_manager_error_quark           (void);
     61GType               gdm_user_manager_get_type              (void);
     62
     63GdmUserManager *    gdm_user_manager_new                   (void);
     64
     65gboolean            gdm_user_manager_count_users           (GdmUserManager *user_manager,
     66                                                            gint           *user_count,
     67                                                            GError        **error);
     68
     69gboolean            gdm_user_manager_get_user_list         (GdmUserManager *user_manager,
     70                                                            GArray        **user_list,
     71                                                            GError        **error);
     72
     73gboolean            gdm_user_manager_get_user_info         (GdmUserManager *user_manager,
     74                                                            gint64          uid,
     75                                                            gchar         **user_name,
     76                                                            gchar         **real_name,
     77                                                            gchar         **shell,
     78                                                            gint           *login_count,
     79                                                            gchar         **icon_url,
     80                                                            GError        **error);
     81
     82gboolean            gdm_user_manager_get_users_info        (GdmUserManager *user_manager,
     83                                                            GArray         *uids,
     84                                                            GPtrArray     **user_info,
     85                                                            GError        **error);
     86
     87gboolean            gdm_user_manager_get_users_loaded      (GdmUserManager *user_manager,
     88                                                            gboolean       *is_loaded,
     89                                                            GError        **error);
     90
     91G_END_DECLS
     92
     93#endif /* __GDM_USER_MANAGER_H */
  • daemon/gdm-user-manager.xml

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/gdm-user-manager.xml gdm-2.28.0.new/daemon/gdm-user-manager.xml
    old new  
     1<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
     2<node name="/org/gnome/DisplayManager/UserManager">
     3  <interface name="org.gnome.DisplayManager.UserManager">
     4
     5    <!-- Get the number of known users -->
     6    <method name="CountUsers">
     7      <arg name="user_count" direction="out" type="i"/>
     8    </method>
     9   
     10    <!-- Get the list of known UIDs -->
     11    <method name="GetUserList">
     12      <arg name="uids" direction="out" type="ax"/>
     13    </method>
     14
     15    <!-- Get user info for a user -->
     16    <method name="GetUserInfo">
     17      <arg name="uid" direction="in" type="x"/>
     18      <arg name="user_name" direction="out" type="s"/>
     19      <arg name="real_name" direction="out" type="s"/>
     20      <arg name="shell" direction="out" type="s"/>
     21      <arg name="login_count" direction="out" type="i"/>     
     22      <arg name="icon_url" direction="out" type="s"/>
     23    </method>
     24
     25    <!-- Get user info for a list of users -->
     26    <method name="GetUsersInfo">
     27      <arg name="uid" direction="in" type="ax"/>
     28      <!-- (uid, user_name, real_name, shell, login_count, icon_url) -->
     29      <arg name="user_info" direction="out" type="a(xsssis)"/>
     30    </method>
     31   
     32    <!-- Query if the initial user list is loaded -->
     33    <method name="GetUsersLoaded">
     34      <arg name="is_loaded" direction="out" type="b"/>
     35    </method>
     36
     37    <!-- Triggered when the initial user list is loaded -->
     38    <signal name="UsersLoaded" />
     39
     40    <!-- Triggered when a users are added to/removed from the system.
     41         Clients should monitor these signals as soon as they connect to
     42         this object -->
     43    <signal name="UserAdded">
     44      <arg name="uid" type="x"/>
     45    </signal>
     46    <signal name="UserRemoved">
     47      <arg name="uid" type="x"/>
     48    </signal>
     49
     50    <!-- Triggered when a user has updated information -->
     51    <signal name="UserUpdated">
     52      <arg name="uid" type="x"/>
     53    </signal>
     54   
     55  </interface>
     56</node>
  • daemon/gdm-user-private.h

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/gdm-user-private.h gdm-2.28.0.new/daemon/gdm-user-private.h
    old new  
     1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
     2 *
     3 * Copyright (C) 2004-2005 James M. Cape <jcape@ignore-your.tv>.
     4 *
     5 * This program is free software; you can redistribute it and/or modify
     6 * it under the terms of the GNU General Public License as published by
     7 * the Free Software Foundation; either version 2 of the License, or
     8 * (at your option) any later version.
     9 *
     10 * This program is distributed in the hope that it will be useful,
     11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13 * GNU General Public License for more details.
     14 *
     15 * You should have received a copy of the GNU General Public License
     16 * along with this program; if not, write to the Free Software
     17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 */
     19
     20/*
     21 * Private interfaces to the GdmUser object
     22 */
     23
     24#ifndef __GDM_USER_PRIVATE__
     25#define __GDM_USER_PRIVATE__ 1
     26
     27#include <pwd.h>
     28
     29#include "gdm-user.h"
     30
     31G_BEGIN_DECLS
     32
     33void _gdm_user_update           (GdmUser             *user,
     34                                 const struct passwd *pwent);
     35void _gdm_user_add_session      (GdmUser             *user,
     36                                 const char          *session_id);
     37void _gdm_user_remove_session   (GdmUser             *user,
     38                                 const char          *session_id);
     39
     40G_END_DECLS
     41
     42#endif /* !__GDM_USER_PRIVATE__ */
  • daemon/main.c

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/main.c gdm-2.28.0.new/daemon/main.c
    old new  
    4343#include <dbus/dbus-glib.h>
    4444#include <dbus/dbus-glib-lowlevel.h>
    4545
     46#include "gdm-user-manager.h"
    4647#include "gdm-manager.h"
    4748#include "gdm-log.h"
    4849#include "gdm-common.h"
     
    5960
    6061extern char **environ;
    6162
     63static GdmUserManager  *user_manager  = NULL;
    6264static GdmManager      *manager       = NULL;
    6365static GdmSettings     *settings      = NULL;
    6466static uid_t            gdm_uid       = -1;
     
    576578                goto out;
    577579        }
    578580
     581        user_manager = gdm_user_manager_new ();
     582        if (user_manager == NULL) {
     583                g_warning ("Could not construct user manager object");
     584                exit (1);
     585        }
     586
    579587        if (! gdm_settings_direct_init (settings, GDMCONFDIR "/gdm.schemas", "/")) {
    580588                g_warning ("Unable to initialize settings");
    581589                goto out;
  • daemon/Makefile.am

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/daemon/Makefile.am gdm-2.28.0.new/daemon/Makefile.am
    old new  
    99        -DDATADIR=\"$(datadir)\"                        \
    1010        -DDMCONFDIR=\"$(dmconfdir)\"                    \
    1111        -DGDMCONFDIR=\"$(gdmconfdir)\"                  \
     12        -DCACHEDIR=\"$(cachedir)\"                      \
    1213        -DLIBDIR=\"$(libdir)\"                          \
    1314        -DLIBEXECDIR=\"$(libexecdir)\"                  \
    1415        -DLOGDIR=\"$(logdir)\"                          \
     
    3435        gdm-session-direct-glue.h               \
    3536        gdm-manager-glue.h                      \
    3637        gdm-display-glue.h                      \
     38        gdm-user-manager-glue.h                 \
    3739        gdm-xdmcp-greeter-display-glue.h        \
    3840        gdm-xdmcp-chooser-display-glue.h        \
    3941        gdm-static-display-glue.h               \
     
    4547
    4648gdm-manager-glue.h: gdm-manager.xml Makefile.am
    4749        dbus-binding-tool --prefix=gdm_manager --mode=glib-server --output=gdm-manager-glue.h $(srcdir)/gdm-manager.xml
     50gdm-user-manager-glue.h: gdm-user-manager.xml Makefile.am
     51        dbus-binding-tool --prefix=gdm_user_manager --mode=glib-server --output=gdm-user-manager-glue.h $(srcdir)/gdm-user-manager.xml
    4852gdm-slave-glue.h: gdm-slave.xml Makefile.am
    4953        dbus-binding-tool --prefix=gdm_slave --mode=glib-server --output=gdm-slave-glue.h $(srcdir)/gdm-slave.xml
    5054gdm-simple-slave-glue.h: gdm-simple-slave.xml Makefile.am
     
    303307        gdm-product-display.h           \
    304308        gdm-manager.c                   \
    305309        gdm-manager.h                   \
     310        gdm-user.c                      \
     311        gdm-user.h                      \
     312        gdm-user-private.h              \
     313        gdm-user-manager.c              \
     314        gdm-user-manager.h              \
    306315        gdm-slave-proxy.c               \
    307316        gdm-slave-proxy.h               \
    308317        $(NULL)
     
    365374        gdm-session-direct.xml          \
    366375        gdm-manager.xml                 \
    367376        gdm-display.xml                 \
     377        gdm-user-manager.xml            \
    368378        gdm-xdmcp-greeter-display.xml   \
    369379        gdm-xdmcp-chooser-display.xml   \
    370380        gdm-static-display.xml          \
  • data/gdm.conf.in

    diff -Nur -x '*.orig' -x '*~' gdm-2.28.0/data/gdm.conf.in gdm-2.28.0.new/data/gdm.conf.in
    old new  
    88    <allow own="org.gnome.DisplayManager"/>
    99
    1010    <allow send_destination="org.gnome.DisplayManager"
     11           send_interface="org.gnome.DisplayManager.UserManager"/>
     12    <allow send_destination="org.gnome.DisplayManager"
    1113           send_interface="org.gnome.DisplayManager.Manager"/>
    1214    <allow send_destination="org.gnome.DisplayManager"
    1315           send_interface="org.gnome.DisplayManager.Display"/>
     
    2830
    2931  <policy context="default">
    3032    <deny send_destination="org.gnome.DisplayManager"
     33          send_interface="org.gnome.DisplayManager.UserManager"/>
     34    <deny send_destination="org.gnome.DisplayManager"
    3135          send_interface="org.gnome.DisplayManager.Manager"/>
    3236    <deny send_destination="org.gnome.DisplayManager"
    3337          send_interface="org.gnome.DisplayManager.Display"/>
     
    7175    <allow send_destination="org.gnome.DisplayManager"
    7276           send_interface="org.gnome.DisplayManager.LocalDisplayFactory"
    7377           send_member="StartGuestSession"/>
     78           
     79    <allow send_destination="org.gnome.DisplayManager"
     80           send_interface="org.gnome.DisplayManager.UserManager"
     81           send_member="CountUsers"/>
     82    <allow send_destination="org.gnome.DisplayManager"
     83           send_interface="org.gnome.DisplayManager.UserManager"
     84           send_member="GetUsersLoaded"/>
     85    <allow send_destination="org.gnome.DisplayManager"
     86           send_interface="org.gnome.DisplayManager.UserManager"
     87           send_member="GetUserList"/>
     88    <allow send_destination="org.gnome.DisplayManager"
     89           send_interface="org.gnome.DisplayManager.UserManager"
     90           send_member="GetUserInfo"/>
     91    <allow send_destination="org.gnome.DisplayManager"
     92           send_interface="org.gnome.DisplayManager.UserManager"
     93           send_member="GetUsersInfo"/>
    7494
    7595    <allow send_destination="org.gnome.DisplayManager"
    7696           send_interface="org.gnome.DisplayManager.Manager"
     
    80100
    81101  <policy user="@GDM_USERNAME@">
    82102    <allow send_destination="org.gnome.DisplayManager"
     103           send_interface="org.gnome.DisplayManager.UserManager"/> 
     104    <allow send_destination="org.gnome.DisplayManager"
    83105           send_interface="org.gnome.DisplayManager.Manager"/>
    84106    <allow send_destination="org.gnome.DisplayManager"
    85107           send_interface="org.gnome.DisplayManager.Display"/>
Note: See TracBrowser for help on using the repository browser.