From e9a33290544894ff65dd92b277403eb4829c9785 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 18 Feb 2011 18:39:47 -0500 Subject: [PATCH] - Fix user list async bugs by dropping async code and moving to accounts service library Resolves: #678236 - Add requires for accounts service to spec since it isn't optional (and hasn't been for a while) --- gdm-multistack.patch | 101 +- gdm.spec | 12 +- move-to-accounts-library.patch | 3961 ++++++++++++++++++++++++++++++++ 3 files changed, 4022 insertions(+), 52 deletions(-) create mode 100644 move-to-accounts-library.patch diff --git a/gdm-multistack.patch b/gdm-multistack.patch index ef8dc9a..6fd5ce5 100644 --- a/gdm-multistack.patch +++ b/gdm-multistack.patch @@ -1,4 +1,4 @@ -From bfe82193e0ffdc8434000e0a409ad8f4858f8941 Mon Sep 17 00:00:00 2001 +From d8945b88ee774a96db43ef743db49d1a91f44d33 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 22 Jul 2010 13:38:09 -0400 Subject: [PATCH 01/35] Revert "Don't wait a mandatory 2 seconds when resetting greeter" @@ -28,7 +28,7 @@ index e6b3c98..9ea5bc9 100644 1.7.4.1 -From f9fb5f69d92799e2df7e4756716f1a092464c50f Mon Sep 17 00:00:00 2001 +From 9f8735086e8b32b64460797183595d058203ebf1 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 7 Jul 2010 17:16:38 -0400 Subject: [PATCH 02/35] Don't set list-visible unless the widget is visible @@ -62,7 +62,7 @@ index ebbfdb9..e81bd77 100644 1.7.4.1 -From 8723117094dc995c755fb9c194c10f011d724f01 Mon Sep 17 00:00:00 2001 +From 95513b3697900f71e769b5a1948be557ecd64757 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 28 Jun 2010 14:35:35 -0400 Subject: [PATCH 03/35] Add user chooser to ui file @@ -157,7 +157,7 @@ index 8409166..7ce166b 100644 1.7.4.1 -From 5b384978830352baff78433b4584d88ade679bd8 Mon Sep 17 00:00:00 2001 +From b18cc72457e6abde22a8423a80cde831efd677c5 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 20 Feb 2009 14:05:20 -0500 Subject: [PATCH 04/35] Add new api to ask when chooser widget is done loading items @@ -213,7 +213,7 @@ index 11a6456..3f6fea3 100644 1.7.4.1 -From 284784301a26480e350678716efaa7a6f956ed2c Mon Sep 17 00:00:00 2001 +From f54cca866610069e51ef4bcdb7c0fe1f9ba76964 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Mar 2009 11:19:40 -0500 Subject: [PATCH 05/35] Create session settings object up front @@ -249,7 +249,7 @@ index 3dd714f..9adb0de 100644 1.7.4.1 -From d22a6da1635c6cfcfd9c7b7017a283da62a597c9 Mon Sep 17 00:00:00 2001 +From 0ab65e8c6ca52f4785f2466cce7f7507d88fc9c3 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 13 Jul 2010 22:42:43 -0400 Subject: [PATCH 06/35] disconnect signal handlers in destroy session @@ -388,7 +388,7 @@ index 9ea5bc9..d37cc79 100644 1.7.4.1 -From b16c63af9e95e2b654f35200532be9aa81a0c733 Mon Sep 17 00:00:00 2001 +From acdd83e5a3fd6e135eed33706824123d53ba3357 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 16 Jan 2009 11:00:08 -0500 Subject: [PATCH 07/35] Introduce new Conversation object @@ -1458,7 +1458,7 @@ index 8bed085..9bfda86 100644 1.7.4.1 -From 16e0827700e1b871564a6f576885c7649579f4ba Mon Sep 17 00:00:00 2001 +From be4f83a6b936d7f73614accd78cf10c78e4b257b Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Feb 2009 10:55:03 -0500 Subject: [PATCH 08/35] Rename session worker to the service it's managing @@ -1647,7 +1647,7 @@ index d24f025..4833f23 100644 1.7.4.1 -From cf7b821e28dc5bf19e3894aec55a0b131e1948f0 Mon Sep 17 00:00:00 2001 +From 791bd408970f023cca1211d21400e7f73d3a557c Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 16 Jan 2009 13:01:48 -0500 Subject: [PATCH 09/35] Make greeter/autologin session explicitly request PAM conversation @@ -2008,7 +2008,7 @@ index 7be5acd..ed20884 100644 1.7.4.1 -From 3175d2a8e4b985a8a67f5e8a345617e9d1ac17f0 Mon Sep 17 00:00:00 2001 +From 90eb845b64bb5668aeb2d54eb78a7c2d4892778d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 16 Jan 2009 15:18:31 -0500 Subject: [PATCH 10/35] Store multiple conversations in the session @@ -6615,7 +6615,7 @@ index ed20884..16f8db5 100644 1.7.4.1 -From 4234b610a8874324fdb86062de631da640ee38ad Mon Sep 17 00:00:00 2001 +From 9f4212f9ea630e7b30b00ccf86a882b91e3b5c17 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 28 Oct 2009 16:05:14 -0400 Subject: [PATCH 11/35] Return a different error code for "service won't work" than "auth failed" @@ -6675,7 +6675,7 @@ index ee5465a..b1c8285 100644 1.7.4.1 -From 2647bdf50d3ab9d992d7db3249dedbebb95b3925 Mon Sep 17 00:00:00 2001 +From 9e9a68065a829025da372b034868cfc0ca4971a1 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 28 Oct 2009 21:32:00 -0400 Subject: [PATCH 12/35] Emit "service-unavailable" from session when pam service refuses to work @@ -6914,7 +6914,7 @@ index 9e72f89..ab16031 100644 1.7.4.1 -From 00dcd646370958bd2500c6d4890dd62a8e42dd63 Mon Sep 17 00:00:00 2001 +From 12dbb74e8cd44eb579587469d6e376f419056ff4 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 28 Oct 2009 21:38:52 -0400 Subject: [PATCH 13/35] Bubble service-unavailable up to greeter @@ -7048,7 +7048,7 @@ index 396007f..7d967b3 100644 1.7.4.1 -From 9494ef0f580ee708be0d3c1efbf2c96aed28a5ec Mon Sep 17 00:00:00 2001 +From 8c7b68952240df1c40a7f14c5868665a365ff64f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 28 Oct 2009 21:46:39 -0400 Subject: [PATCH 14/35] Catch service-unavailable from server in client and propagate it @@ -7127,7 +7127,7 @@ index 868b496..63bd4b5 100644 1.7.4.1 -From cabbd657ff61c2ee3c5b3dc849628f1ae2ac9b03 Mon Sep 17 00:00:00 2001 +From 6489e96641ee835a7c0fb22010e66fbf82ce3db8 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Thu, 5 Feb 2009 15:20:25 -0500 Subject: [PATCH 15/35] Queue a greeter reset when the user clicks cancel @@ -7252,7 +7252,7 @@ index 7d967b3..2ecf0a4 100644 1.7.4.1 -From 2aa8d609e1617b8e42bdac773f98582cd4473ab0 Mon Sep 17 00:00:00 2001 +From e3efa1719fdb78952cf57e28647cc52fe7844957 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Nov 2009 13:35:26 -0500 Subject: [PATCH 16/35] Don't delay login for passwd -d users @@ -7281,7 +7281,7 @@ index a64bbc2..d689d91 100644 1.7.4.1 -From 4f2908ab972ed543a50455f2b1b52953cbc95741 Mon Sep 17 00:00:00 2001 +From b0a3cad225154377fa0e5429ebe4525d5f7e291e Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 30 Jan 2009 23:57:31 -0500 Subject: [PATCH 17/35] Add a plugin based extension system to greeter @@ -7356,7 +7356,7 @@ index d5455e1..d8a9e72 100644 VOID:DOUBLE +BOOLEAN:STRING diff --git a/configure.ac b/configure.ac -index fe612e7..8a423bb 100644 +index 48be019..2a2e37b 100644 --- a/configure.ac +++ b/configure.ac @@ -18,6 +18,22 @@ AC_PROG_CXX @@ -7382,7 +7382,7 @@ index fe612e7..8a423bb 100644 AC_HEADER_STDC AC_SUBST(VERSION) -@@ -192,6 +208,15 @@ AC_ARG_WITH(dmconfdir, +@@ -193,6 +209,15 @@ AC_ARG_WITH(dmconfdir, AC_SUBST(dmconfdir) dnl --------------------------------------------------------------------------- @@ -7398,7 +7398,7 @@ index fe612e7..8a423bb 100644 dnl - Configure arguments dnl --------------------------------------------------------------------------- -@@ -1268,6 +1293,21 @@ fi +@@ -1269,6 +1294,21 @@ fi AC_SUBST(GDM_SCREENSHOT_DIR) @@ -7420,7 +7420,7 @@ index fe612e7..8a423bb 100644 dnl --------------------------------------------------------------------------- dnl - Finish -@@ -1395,6 +1435,10 @@ daemon/Makefile +@@ -1396,6 +1436,10 @@ daemon/Makefile docs/Makefile gui/Makefile gui/simple-greeter/Makefile @@ -7432,7 +7432,7 @@ index fe612e7..8a423bb 100644 utils/Makefile data/gdm.conf diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am -index aa78504..f0ff206 100644 +index a842c7b..d5e68a2 100644 --- a/gui/simple-greeter/Makefile.am +++ b/gui/simple-greeter/Makefile.am @@ -1,8 +1,13 @@ @@ -7457,7 +7457,7 @@ index aa78504..f0ff206 100644 $(DISABLE_DEPRECATED_CFLAGS) \ $(GTK_CFLAGS) \ $(SIMPLE_GREETER_CFLAGS) \ -@@ -83,10 +89,17 @@ test_greeter_login_window_SOURCES = \ +@@ -60,10 +66,17 @@ test_greeter_login_window_SOURCES = \ gdm-user-chooser-widget.c \ gdm-user-chooser-dialog.h \ gdm-user-chooser-dialog.c \ @@ -7472,10 +7472,10 @@ index aa78504..f0ff206 100644 test_greeter_login_window_LDADD = \ $(top_builddir)/common/libgdmcommon.la \ + $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \ - libgdmuser.la \ $(COMMON_LIBS) \ $(SIMPLE_GREETER_LIBS) \ -@@ -128,6 +141,7 @@ test_greeter_panel_SOURCES = \ + $(RBAC_LIBS) \ +@@ -104,6 +117,7 @@ test_greeter_panel_SOURCES = \ test_greeter_panel_LDADD = \ $(top_builddir)/common/libgdmcommon.la \ @@ -7483,7 +7483,7 @@ index aa78504..f0ff206 100644 $(SIMPLE_GREETER_LIBS) \ $(GTK_LIBS) \ $(GCONF_LIBS) \ -@@ -271,17 +285,24 @@ gdm_simple_greeter_SOURCES = \ +@@ -245,16 +259,23 @@ gdm_simple_greeter_SOURCES = \ gdm-language-chooser-dialog.c \ gdm-language-option-widget.h \ gdm-language-option-widget.c \ @@ -7503,7 +7503,6 @@ index aa78504..f0ff206 100644 gdm_simple_greeter_LDADD = \ $(top_builddir)/common/libgdmcommon.la \ - libgdmuser.la \ + $(top_builddir)/gui/simple-greeter/libgdmsimplegreeter/libgdmsimplegreeter.la \ $(COMMON_LIBS) \ $(EXTRA_GREETER_LIBS) \ @@ -10938,10 +10937,10 @@ index 0000000..cc377bd + +#endif /* __GDM_TASK_LIST_H */ diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c -index 9447e59..136194a 100644 +index a385218..8414313 100644 --- a/gui/simple-greeter/gdm-user-chooser-widget.c +++ b/gui/simple-greeter/gdm-user-chooser-widget.c -@@ -371,9 +371,30 @@ gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget, +@@ -635,9 +635,30 @@ gdm_user_chooser_widget_set_show_user_auto (GdmUserChooserWidget *widget, char * gdm_user_chooser_widget_get_chosen_user_name (GdmUserChooserWidget *widget) { @@ -12313,7 +12312,7 @@ index 8a4997a..2f9af97 100644 1.7.4.1 -From 8b0c7fb9df4c51983bdc745e4ab0450cc4b7610e Mon Sep 17 00:00:00 2001 +From a659374376aa864925143b7b58847aca9e830345 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Aug 2010 18:25:50 -0400 Subject: [PATCH 18/35] squash with password @@ -12378,7 +12377,7 @@ index 255283e..11a171c 100644 1.7.4.1 -From 8aaa69fab5eecab0049b7bfe09c493cee2daccc1 Mon Sep 17 00:00:00 2001 +From 047ceabcb1fa549e9a6bb7197c5e12cdd4e49296 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Aug 2010 11:13:10 -0400 Subject: [PATCH 19/35] task list fix @@ -12428,7 +12427,7 @@ index 5fdc2b8..3e49fb7 100644 1.7.4.1 -From ab1ee02f38bcde2f7f999570c3b13725f096d20a Mon Sep 17 00:00:00 2001 +From 1055ba4d586d4f61a22faca0d968ddb8816b5569 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 29 Jun 2010 14:13:35 -0400 Subject: [PATCH 20/35] Show cancel button after first message @@ -12472,7 +12471,7 @@ index 9844af9..938e523 100644 1.7.4.1 -From 20da8b82b8a4fd0d0233d8e3ecc05dd97af6a852 Mon Sep 17 00:00:00 2001 +From 72355ea96c482d015422b327c5ecca3b3766478d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 28 Oct 2009 11:13:10 -0400 Subject: [PATCH 21/35] Prevent start session signal handler from getting called multiple times @@ -12508,7 +12507,7 @@ index 938e523..0fb6c64 100644 1.7.4.1 -From 2645ecce2175231378170af39e08cf244f76d925 Mon Sep 17 00:00:00 2001 +From 889691316c708a787a5f60e91e380c658893542d Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Feb 2009 16:25:47 -0500 Subject: [PATCH 22/35] Add fingerprint plugin @@ -12544,10 +12543,10 @@ fingerprint scans. create mode 100644 gui/simple-greeter/plugins/fingerprint/plugin.c diff --git a/configure.ac b/configure.ac -index 8a423bb..be1ff01 100644 +index 2a2e37b..98a8bf6 100644 --- a/configure.ac +++ b/configure.ac -@@ -1439,6 +1439,10 @@ gui/simple-greeter/libgdmsimplegreeter/Makefile +@@ -1440,6 +1440,10 @@ gui/simple-greeter/libgdmsimplegreeter/Makefile gui/simple-greeter/libgdmsimplegreeter/gdmsimplegreeter.pc gui/simple-greeter/plugins/Makefile gui/simple-greeter/plugins/password/Makefile @@ -13278,7 +13277,7 @@ index 2f9af97..4f5b317 100644 1.7.4.1 -From d197aa8a487a2ec249cc6dfd0c993bde13f22389 Mon Sep 17 00:00:00 2001 +From 65dd58cf8a77e2df4e517d23aefc7e7f2a186231 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Feb 2009 16:25:47 -0500 Subject: [PATCH 23/35] Add smartcard plugin @@ -13324,7 +13323,7 @@ smartcards are inserted. create mode 100644 gui/simple-greeter/plugins/smartcard/plugin.c diff --git a/configure.ac b/configure.ac -index be1ff01..1048e3c 100644 +index 98a8bf6..5f370ab 100644 --- a/configure.ac +++ b/configure.ac @@ -68,6 +68,7 @@ LIBCANBERRA_GTK_REQUIRED_VERSION=0.4 @@ -13348,7 +13347,7 @@ index be1ff01..1048e3c 100644 PKG_CHECK_MODULES(XLIB, x11 xau, , [AC_PATH_XTRA if test "x$no_x" = xyes; then -@@ -1443,6 +1450,10 @@ gui/simple-greeter/plugins/fingerprint/Makefile +@@ -1444,6 +1451,10 @@ gui/simple-greeter/plugins/fingerprint/Makefile gui/simple-greeter/plugins/fingerprint/icons/Makefile gui/simple-greeter/plugins/fingerprint/icons/16x16/Makefile gui/simple-greeter/plugins/fingerprint/icons/48x48/Makefile @@ -16794,7 +16793,7 @@ index 4f5b317..48634f1 100644 1.7.4.1 -From 82fbee221f78718703481ae9b28933d81c7a2011 Mon Sep 17 00:00:00 2001 +From d52b686f0869887997864ea0553f3f5785f65b94 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Aug 2010 18:26:01 -0400 Subject: [PATCH 24/35] squash with smartcard @@ -16835,7 +16834,7 @@ index b925f5e..b40a21c 100644 1.7.4.1 -From 7e8cb867f0f73a1208e773bb7b09b57ba0d3a759 Mon Sep 17 00:00:00 2001 +From 6977055677ac889d204d17391327261e7dd1757f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 21 Apr 2009 10:25:18 -0400 Subject: [PATCH 25/35] When one PAM conversation wins, stop the others @@ -16967,7 +16966,7 @@ index 2ecf0a4..ff1f3af 100644 1.7.4.1 -From 01c711f4bc117d8c67eb1f78b56c3b3220d7371e Mon Sep 17 00:00:00 2001 +From 78949a4384dc2aae51bb8835520075bcc9793ef6 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 24 Jul 2009 14:41:48 -0400 Subject: [PATCH 26/35] KILL stuck processes if they don't die on TERM @@ -17091,7 +17090,7 @@ index be85f30..8b93663 100644 1.7.4.1 -From ea0473ddf20f19d9506cac45a3d1dae85af62e42 Mon Sep 17 00:00:00 2001 +From 2316076b232cd4efd6e6e6f22c6af206ff7bb581 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 13 Jul 2010 22:36:19 -0400 Subject: [PATCH 27/35] add better debug spew (needs squash) @@ -17144,7 +17143,7 @@ index 0f0c053..23812d2 100644 1.7.4.1 -From e8dffd5eb064b91a361333ffbfec661f1cc8f10a Mon Sep 17 00:00:00 2001 +From b98e46ec2d16d390c5fecf0b18471583ca54670f Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 13 Jul 2010 22:37:35 -0400 Subject: [PATCH 28/35] switch to proper mode when going to timed login @@ -17170,7 +17169,7 @@ index 0fb6c64..adcd71f 100644 1.7.4.1 -From 31362325aaffea2632c21d42de137e64f560db44 Mon Sep 17 00:00:00 2001 +From 16c4f635f7442808d4f3f7f9232097b8bb093345 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Tue, 3 Aug 2010 15:21:26 -0400 Subject: [PATCH 29/35] Drop "Cancelling" message for plugin initiated cancels @@ -17199,7 +17198,7 @@ index adcd71f..cd1941e 100644 1.7.4.1 -From 878951bf14c64b9103722ddebad9c8b4ea1023ad Mon Sep 17 00:00:00 2001 +From 40114bb382490be345b04004082c85d55cf53691 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Aug 2010 18:11:27 -0400 Subject: [PATCH 30/35] drop code for label that doesn't exist anymore @@ -17235,7 +17234,7 @@ index cd1941e..f3f89b2 100644 1.7.4.1 -From 8fca2ce5f0c8e7d3b9c491cb0bbac131582ae9dc Mon Sep 17 00:00:00 2001 +From 5cb876a52cd54a895dc925fc8625a4b4c490f4e9 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Aug 2010 18:03:52 -0400 Subject: [PATCH 31/35] Add delay when showing messages (needs split) @@ -17700,7 +17699,7 @@ index b40a21c..5e234b9 100644 1.7.4.1 -From 5a300c3cf9f73682c7209032193fc1b84442ad18 Mon Sep 17 00:00:00 2001 +From 438a429d75d0af77649901c2421e2898a504f831 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Wed, 4 Aug 2010 19:27:14 -0400 Subject: [PATCH 32/35] Drop cancelling message @@ -17727,7 +17726,7 @@ index e43449e..cb03d06 100644 1.7.4.1 -From 203cf6865fda36f3b31db67ce1e316659c869134 Mon Sep 17 00:00:00 2001 +From 6720d05d54ec542dc9031f13462438fa5b8ebdf4 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Fri, 6 Aug 2010 11:14:23 -0400 Subject: [PATCH 33/35] manage tasks outside of task list @@ -18528,7 +18527,7 @@ index cb03d06..627a6f9 100644 1.7.4.1 -From 73a39fd1baf58a88e9c01eb8815f662d2c1380e0 Mon Sep 17 00:00:00 2001 +From 62d27058a556a1e27099684470f9b24c97f011eb Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 9 Aug 2010 18:09:19 -0400 Subject: [PATCH 34/35] hide task actions more aggressively @@ -18563,7 +18562,7 @@ index 627a6f9..8772fdd 100644 1.7.4.1 -From 58e5e724f54f1dffc20671b8131d8a4c7b354dcc Mon Sep 17 00:00:00 2001 +From 9255529aa654bd240db39888d1fd452d44ec9df3 Mon Sep 17 00:00:00 2001 From: Gal Hammer Date: Thu, 21 Oct 2010 10:14:32 -0400 Subject: [PATCH 35/35] smartcard: don't show extension if disabled in authconfig diff --git a/gdm.spec b/gdm.spec index 2a14cd8..ccdb268 100644 --- a/gdm.spec +++ b/gdm.spec @@ -15,7 +15,7 @@ Summary: The GNOME Display Manager Name: gdm Version: 2.91.6 -Release: 9%{?dist} +Release: 10%{?dist} Epoch: 1 License: GPLv2+ Group: User Interface/X @@ -42,6 +42,7 @@ Requires: xorg-x11-server-utils Requires: setxkbmap Requires: xorg-x11-xinit Requires: ConsoleKit >= %{consolekit_version} +Requires: accountsservice Requires: gnome-settings-daemon >= 2.21.92 Requires: iso-codes Requires: gnome-session @@ -93,6 +94,7 @@ Patch2: plymouth.patch Patch3: fix-theme-related-crash.patch Patch4: fix-crasher.patch Patch5: add-session-chooser.patch +Patch6: move-to-accounts-library.patch Patch96: gdm-multistack.patch # Fedora-specific @@ -127,6 +129,7 @@ The GDM fingerprint plugin provides functionality necessary to use a fingerprint %patch3 -p1 -b .fix-theme-related-crash %patch4 -p1 -b .fix-crasher %patch5 -p1 -b .add-session-chooser +%patch6 -p1 -b .move-to-accounts-library %patch96 -p1 -b .multistack %patch99 -p1 -b .fedora-logo @@ -366,6 +369,13 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor >&/dev/ull || : %{_libdir}/gdm/simple-greeter/plugins/fingerprint.so %changelog +* Fri Feb 18 2011 Ray Strode 2.91.6-10 +- Fix user list async bugs by dropping async code and + moving to accounts service library + Resolves: #678236 +- Add requires for accounts service to spec since it isn't + optional (and hasn't been for a while) + * Thu Feb 17 2011 Ray Strode 2.91.6-9 - Add back session chooser Resolves: #539638 diff --git a/move-to-accounts-library.patch b/move-to-accounts-library.patch new file mode 100644 index 0000000..7596555 --- /dev/null +++ b/move-to-accounts-library.patch @@ -0,0 +1,3961 @@ +From 4dad44a175493f1c495a90ba67270ba11c9c1802 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 18 Feb 2011 17:56:09 -0500 +Subject: [PATCH 1/2] greeter: fix swapped LHS/RHS in icon loading error path + +This nasty bug means in some obscure cases we're going to +end up using freed memory. +--- + gui/simple-greeter/gdm-user-chooser-widget.c | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c +index 9447e59..4b5a80f 100644 +--- a/gui/simple-greeter/gdm-user-chooser-widget.c ++++ b/gui/simple-greeter/gdm-user-chooser-widget.c +@@ -900,7 +900,7 @@ get_pixbuf_from_icon_names (GdmUserChooserWidget *widget, + TRUE, 8, 1, 1, 1, NULL, NULL); + scaled_pixbuf = gdk_pixbuf_scale_simple (pixbuf, size, size, GDK_INTERP_NEAREST); + g_object_unref (pixbuf); +- scaled_pixbuf = pixbuf; ++ pixbuf = scaled_pixbuf; + } + + return pixbuf; +-- +1.7.4.1 + + +From ec034f78dcb27baf240658323892ac2a665c6580 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 18 Feb 2011 17:54:08 -0500 +Subject: [PATCH 2/2] greeter: port to account service library + +The current user manager code is a mess of dbus code for +talking to the accounts daemon and code for falling back if +it isn't there. The accounts daemon is no longer optional, +so drop all that and just use the accounts service library +directly. +--- + configure.ac | 1 + + gui/simple-greeter/Makefile.am | 27 - + gui/simple-greeter/gdm-user-chooser-widget.c | 370 +++- + gui/simple-greeter/gdm-user-manager.c | 3082 -------------------------- + gui/simple-greeter/gdm-user-manager.h | 91 - + gui/simple-greeter/test-user-manager.c | 27 +- + 6 files changed, 316 insertions(+), 3282 deletions(-) + delete mode 100644 gui/simple-greeter/gdm-user-manager.c + delete mode 100644 gui/simple-greeter/gdm-user-manager.h + +diff --git a/configure.ac b/configure.ac +index fe612e7..48be019 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -125,6 +125,7 @@ PKG_CHECK_MODULES(SIMPLE_GREETER, + gtk+-3.0 >= $GTK_REQUIRED_VERSION + gconf-2.0 >= $GCONF_REQUIRED_VERSION + fontconfig >= $FONTCONFIG_REQUIRED_VERSION ++ accountsservice >= $ACCOUNTS_SERVICE_REQUIRED_VERSION + x11 + ) + SIMPLE_GREETER_LIBS="$SIMPLE_GREETER_LIBS -lm" +diff --git a/gui/simple-greeter/Makefile.am b/gui/simple-greeter/Makefile.am +index aa78504..a842c7b 100644 +--- a/gui/simple-greeter/Makefile.am ++++ b/gui/simple-greeter/Makefile.am +@@ -26,29 +26,6 @@ schemasdir = @GCONF_SCHEMA_FILE_DIR@ + schemas_in_files = gdm-simple-greeter.schemas.in + schemas_DATA = $(schemas_in_files:.schemas.in=.schemas) + +-noinst_LTLIBRARIES = \ +- libgdmuser.la \ +- $(null) +- +-libgdmuser_la_SOURCES = \ +- gdm-user.c \ +- gdm-user.h \ +- gdm-user-private.h \ +- gdm-user-manager.c \ +- gdm-user-manager.h \ +- $(NULL) +- +-libgdmuser_la_CFLAGS = \ +- $(SIMPLE_GREETER_CFLAGS) \ +- $(NULL) +- +-libgdmuser_la_LIBADD = \ +- $(NULL) +- +-libgdmuser_la_LDFLAGS = \ +- -export-dynamic \ +- $(NULL) +- + noinst_PROGRAMS = \ + test-filesystem-type \ + test-greeter-login-window \ +@@ -87,7 +64,6 @@ test_greeter_login_window_SOURCES = \ + + test_greeter_login_window_LDADD = \ + $(top_builddir)/common/libgdmcommon.la \ +- libgdmuser.la \ + $(COMMON_LIBS) \ + $(SIMPLE_GREETER_LIBS) \ + $(RBAC_LIBS) \ +@@ -216,7 +192,6 @@ test_user_chooser_SOURCES = \ + $(NULL) + + test_user_chooser_LDADD = \ +- libgdmuser.la \ + $(top_builddir)/common/libgdmcommon.la \ + $(COMMON_LIBS) \ + $(SIMPLE_GREETER_LIBS) \ +@@ -227,7 +202,6 @@ test_user_manager_SOURCES = \ + $(NULL) + + test_user_manager_LDADD = \ +- libgdmuser.la \ + $(top_builddir)/common/libgdmcommon.la \ + $(COMMON_LIBS) \ + $(SIMPLE_GREETER_LIBS) \ +@@ -281,7 +255,6 @@ gdm_simple_greeter_SOURCES = \ + + gdm_simple_greeter_LDADD = \ + $(top_builddir)/common/libgdmcommon.la \ +- libgdmuser.la \ + $(COMMON_LIBS) \ + $(EXTRA_GREETER_LIBS) \ + $(SIMPLE_GREETER_LIBS) \ +diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c +index 4b5a80f..a385218 100644 +--- a/gui/simple-greeter/gdm-user-chooser-widget.c ++++ b/gui/simple-greeter/gdm-user-chooser-widget.c +@@ -37,7 +37,9 @@ + + #include + +-#include "gdm-user-manager.h" ++#include ++#include ++ + #include "gdm-user-chooser-widget.h" + #include "gdm-settings-keys.h" + #include "gdm-settings-client.h" +@@ -59,7 +61,7 @@ enum { + + struct GdmUserChooserWidgetPrivate + { +- GdmUserManager *manager; ++ ActUserManager *manager; + GtkIconTheme *icon_theme; + + GSList *users_to_add; +@@ -170,45 +172,307 @@ queue_update_other_user_visibility (GdmUserChooserWidget *widget) + } + + static void ++rounded_rectangle (cairo_t *cr, ++ gdouble aspect, ++ gdouble x, ++ gdouble y, ++ gdouble corner_radius, ++ gdouble width, ++ gdouble height) ++{ ++ gdouble radius; ++ gdouble degrees; ++ ++ radius = corner_radius / aspect; ++ degrees = G_PI / 180.0; ++ ++ cairo_new_sub_path (cr); ++ cairo_arc (cr, ++ x + width - radius, ++ y + radius, ++ radius, ++ -90 * degrees, ++ 0 * degrees); ++ cairo_arc (cr, ++ x + width - radius, ++ y + height - radius, ++ radius, ++ 0 * degrees, ++ 90 * degrees); ++ cairo_arc (cr, ++ x + radius, ++ y + height - radius, ++ radius, ++ 90 * degrees, ++ 180 * degrees); ++ cairo_arc (cr, ++ x + radius, ++ y + radius, ++ radius, ++ 180 * degrees, ++ 270 * degrees); ++ cairo_close_path (cr); ++} ++ ++static cairo_surface_t * ++surface_from_pixbuf (GdkPixbuf *pixbuf) ++{ ++ cairo_surface_t *surface; ++ cairo_t *cr; ++ ++ surface = cairo_image_surface_create (gdk_pixbuf_get_has_alpha (pixbuf) ? ++ CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24, ++ gdk_pixbuf_get_width (pixbuf), ++ gdk_pixbuf_get_height (pixbuf)); ++ cr = cairo_create (surface); ++ gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); ++ cairo_paint (cr); ++ cairo_destroy (cr); ++ ++ return surface; ++} ++ ++/** ++ * go_cairo_convert_data_to_pixbuf: ++ * @src: a pointer to pixel data in cairo format ++ * @dst: a pointer to pixel data in pixbuf format ++ * @width: image width ++ * @height: image height ++ * @rowstride: data rowstride ++ * ++ * Converts the pixel data stored in @src in CAIRO_FORMAT_ARGB32 cairo format ++ * to GDK_COLORSPACE_RGB pixbuf format and move them ++ * to @dst. If @src == @dst, pixel are converted in place. ++ **/ ++ ++static void ++go_cairo_convert_data_to_pixbuf (unsigned char *dst, ++ unsigned char const *src, ++ int width, ++ int height, ++ int rowstride) ++{ ++ int i,j; ++ unsigned int t; ++ unsigned char a, b, c; ++ ++ g_return_if_fail (dst != NULL); ++ ++#define MULT(d,c,a,t) G_STMT_START { t = (a)? c * 255 / a: 0; d = t;} G_STMT_END ++ ++ if (src == dst || src == NULL) { ++ for (i = 0; i < height; i++) { ++ for (j = 0; j < width; j++) { ++#if G_BYTE_ORDER == G_LITTLE_ENDIAN ++ MULT(a, dst[2], dst[3], t); ++ MULT(b, dst[1], dst[3], t); ++ MULT(c, dst[0], dst[3], t); ++ dst[0] = a; ++ dst[1] = b; ++ dst[2] = c; ++#else ++ MULT(a, dst[1], dst[0], t); ++ MULT(b, dst[2], dst[0], t); ++ MULT(c, dst[3], dst[0], t); ++ dst[3] = dst[0]; ++ dst[0] = a; ++ dst[1] = b; ++ dst[2] = c; ++#endif ++ dst += 4; ++ } ++ dst += rowstride - width * 4; ++ } ++ } else { ++ for (i = 0; i < height; i++) { ++ for (j = 0; j < width; j++) { ++#if G_BYTE_ORDER == G_LITTLE_ENDIAN ++ MULT(dst[0], src[2], src[3], t); ++ MULT(dst[1], src[1], src[3], t); ++ MULT(dst[2], src[0], src[3], t); ++ dst[3] = src[3]; ++#else ++ MULT(dst[0], src[1], src[0], t); ++ MULT(dst[1], src[2], src[0], t); ++ MULT(dst[2], src[3], src[0], t); ++ dst[3] = src[0]; ++#endif ++ src += 4; ++ dst += 4; ++ } ++ src += rowstride - width * 4; ++ dst += rowstride - width * 4; ++ } ++ } ++#undef MULT ++} ++ ++static void ++cairo_to_pixbuf (guint8 *src_data, ++ GdkPixbuf *dst_pixbuf) ++{ ++ unsigned char *src; ++ unsigned char *dst; ++ guint w; ++ guint h; ++ guint rowstride; ++ ++ w = gdk_pixbuf_get_width (dst_pixbuf); ++ h = gdk_pixbuf_get_height (dst_pixbuf); ++ rowstride = gdk_pixbuf_get_rowstride (dst_pixbuf); ++ ++ dst = gdk_pixbuf_get_pixels (dst_pixbuf); ++ src = src_data; ++ ++ go_cairo_convert_data_to_pixbuf (dst, src, w, h, rowstride); ++} ++ ++static GdkPixbuf * ++frame_pixbuf (GdkPixbuf *source) ++{ ++ GdkPixbuf *dest; ++ cairo_t *cr; ++ cairo_surface_t *surface; ++ guint w; ++ guint h; ++ guint rowstride; ++ int frame_width; ++ double radius; ++ guint8 *data; ++ ++ frame_width = 2; ++ ++ w = gdk_pixbuf_get_width (source) + frame_width * 2; ++ h = gdk_pixbuf_get_height (source) + frame_width * 2; ++ radius = w / 10; ++ ++ dest = gdk_pixbuf_new (GDK_COLORSPACE_RGB, ++ TRUE, ++ 8, ++ w, ++ h); ++ rowstride = gdk_pixbuf_get_rowstride (dest); ++ ++ ++ data = g_new0 (guint8, h * rowstride); ++ ++ surface = cairo_image_surface_create_for_data (data, ++ CAIRO_FORMAT_ARGB32, ++ w, ++ h, ++ rowstride); ++ cr = cairo_create (surface); ++ cairo_surface_destroy (surface); ++ ++ /* set up image */ ++ cairo_rectangle (cr, 0, 0, w, h); ++ cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); ++ cairo_fill (cr); ++ ++ rounded_rectangle (cr, ++ 1.0, ++ frame_width + 0.5, ++ frame_width + 0.5, ++ radius, ++ w - frame_width * 2 - 1, ++ h - frame_width * 2 - 1); ++ cairo_set_source_rgba (cr, 0.5, 0.5, 0.5, 0.3); ++ cairo_fill_preserve (cr); ++ ++ surface = surface_from_pixbuf (source); ++ cairo_set_source_surface (cr, surface, frame_width, frame_width); ++ cairo_fill (cr); ++ cairo_surface_destroy (surface); ++ ++ cairo_to_pixbuf (data, dest); ++ ++ cairo_destroy (cr); ++ g_free (data); ++ ++ return dest; ++} ++ ++static GdkPixbuf * ++render_user_icon (GdmUserChooserWidget *widget, ++ ActUser *user) ++{ ++ int size; ++ const char *file; ++ GdkPixbuf *pixbuf; ++ GdkPixbuf *framed; ++ ++ pixbuf = NULL; ++ ++ size = get_icon_height_for_widget (GTK_WIDGET (widget)); ++ file = act_user_get_icon_file (user); ++ ++ if (file) { ++ pixbuf = gdk_pixbuf_new_from_file_at_size (file, size, size, NULL); ++ } ++ ++ if (pixbuf == NULL) { ++ GError *error; ++ ++ error = NULL; ++ pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), ++ "avatar-default", ++ size, ++ GTK_ICON_LOOKUP_FORCE_SIZE, ++ &error); ++ if (error != NULL) { ++ g_warning ("%s", error->message); ++ g_error_free (error); ++ } ++ } ++ ++ if (pixbuf != NULL) { ++ framed = frame_pixbuf (pixbuf); ++ g_object_unref (pixbuf); ++ ++ pixbuf = framed; ++ } ++ ++ return pixbuf; ++} ++ ++static void + update_item_for_user (GdmUserChooserWidget *widget, +- GdmUser *user) ++ ActUser *user) + { + GdkPixbuf *pixbuf; + char *tooltip; + gboolean is_logged_in; +- int size; + char *escaped_username; + char *escaped_real_name; + +- if (!gdm_user_is_loaded (user)) { ++ if (!act_user_is_loaded (user)) { + return; + } + +- size = get_icon_height_for_widget (GTK_WIDGET (widget)); +- pixbuf = gdm_user_render_icon (user, size); ++ pixbuf = render_user_icon (widget, user); + + if (pixbuf == NULL && widget->priv->stock_person_pixbuf != NULL) { + pixbuf = g_object_ref (widget->priv->stock_person_pixbuf); + } + + tooltip = g_strdup_printf (_("Log in as %s"), +- gdm_user_get_user_name (user)); ++ act_user_get_user_name (user)); + +- is_logged_in = gdm_user_is_logged_in (user); ++ is_logged_in = act_user_is_logged_in (user); + + g_debug ("GdmUserChooserWidget: User added name:%s logged-in:%d pixbuf:%p", +- gdm_user_get_user_name (user), ++ act_user_get_user_name (user), + is_logged_in, + pixbuf); + +- escaped_username = g_markup_escape_text (gdm_user_get_user_name (user), -1); +- escaped_real_name = g_markup_escape_text (gdm_user_get_real_name (user), -1); ++ escaped_username = g_markup_escape_text (act_user_get_user_name (user), -1); ++ escaped_real_name = g_markup_escape_text (act_user_get_real_name (user), -1); + gdm_chooser_widget_update_item (GDM_CHOOSER_WIDGET (widget), + escaped_username, + pixbuf, + escaped_real_name, + tooltip, +- gdm_user_get_login_frequency (user), ++ act_user_get_login_frequency (user), + is_logged_in, + FALSE); + g_free (escaped_real_name); +@@ -225,7 +489,7 @@ on_item_load (GdmChooserWidget *widget, + const char *id, + GdmUserChooserWidget *user_chooser) + { +- GdmUser *user; ++ ActUser *user; + + g_debug ("GdmUserChooserWidget: Loading item for id=%s", id); + +@@ -241,7 +505,7 @@ on_item_load (GdmChooserWidget *widget, + return; + } + +- user = gdm_user_manager_get_user (user_chooser->priv->manager, id); ++ user = act_user_manager_get_user (user_chooser->priv->manager, id); + if (user != NULL) { + update_item_for_user (user_chooser, user); + } +@@ -467,7 +731,7 @@ is_user_list_disabled (GdmUserChooserWidget *widget) + + static void + add_user (GdmUserChooserWidget *widget, +- GdmUser *user) ++ ActUser *user) + { + GdkPixbuf *pixbuf; + char *tooltip; +@@ -486,18 +750,18 @@ add_user (GdmUserChooserWidget *widget, + } + + tooltip = g_strdup_printf (_("Log in as %s"), +- gdm_user_get_user_name (user)); ++ act_user_get_user_name (user)); + +- is_logged_in = gdm_user_is_logged_in (user); ++ is_logged_in = act_user_is_logged_in (user); + +- escaped_username = g_markup_escape_text (gdm_user_get_user_name (user), -1); +- escaped_real_name = g_markup_escape_text (gdm_user_get_real_name (user), -1); ++ escaped_username = g_markup_escape_text (act_user_get_user_name (user), -1); ++ escaped_real_name = g_markup_escape_text (act_user_get_real_name (user), -1); + gdm_chooser_widget_add_item (GDM_CHOOSER_WIDGET (widget), + escaped_username, + pixbuf, + escaped_real_name, + tooltip, +- gdm_user_get_login_frequency (user), ++ act_user_get_login_frequency (user), + is_logged_in, + FALSE, + (GdmChooserWidgetItemLoadFunc) on_item_load, +@@ -514,8 +778,8 @@ add_user (GdmUserChooserWidget *widget, + } + + static void +-on_user_added (GdmUserManager *manager, +- GdmUser *user, ++on_user_added (ActUserManager *manager, ++ ActUser *user, + GdmUserChooserWidget *widget) + { + /* wait for all users to be loaded */ +@@ -526,19 +790,19 @@ on_user_added (GdmUserManager *manager, + } + + static void +-on_user_removed (GdmUserManager *manager, +- GdmUser *user, ++on_user_removed (ActUserManager *manager, ++ ActUser *user, + GdmUserChooserWidget *widget) + { + const char *user_name; + +- g_debug ("GdmUserChooserWidget: User removed: %s", gdm_user_get_user_name (user)); ++ g_debug ("GdmUserChooserWidget: User removed: %s", act_user_get_user_name (user)); + /* wait for all users to be loaded */ + if (! widget->priv->loaded) { + return; + } + +- user_name = gdm_user_get_user_name (user); ++ user_name = act_user_get_user_name (user); + + gdm_chooser_widget_remove_item (GDM_CHOOSER_WIDGET (widget), + user_name); +@@ -547,17 +811,17 @@ on_user_removed (GdmUserManager *manager, + } + + static void +-on_user_is_logged_in_changed (GdmUserManager *manager, +- GdmUser *user, ++on_user_is_logged_in_changed (ActUserManager *manager, ++ ActUser *user, + GdmUserChooserWidget *widget) + { + const char *user_name; + gboolean is_logged_in; + +- g_debug ("GdmUserChooserWidget: User logged in changed: %s", gdm_user_get_user_name (user)); ++ g_debug ("GdmUserChooserWidget: User logged in changed: %s", act_user_get_user_name (user)); + +- user_name = gdm_user_get_user_name (user); +- is_logged_in = gdm_user_is_logged_in (user); ++ user_name = act_user_get_user_name (user); ++ is_logged_in = act_user_is_logged_in (user); + + gdm_chooser_widget_set_item_in_use (GDM_CHOOSER_WIDGET (widget), + user_name, +@@ -565,8 +829,8 @@ on_user_is_logged_in_changed (GdmUserManager *manager, + } + + static void +-on_user_changed (GdmUserManager *manager, +- GdmUser *user, ++on_user_changed (ActUserManager *manager, ++ ActUser *user, + GdmUserChooserWidget *widget) + { + /* wait for all users to be loaded */ +@@ -612,7 +876,7 @@ queue_add_users (GdmUserChooserWidget *widget) + } + + static void +-on_is_loaded_changed (GdmUserManager *manager, ++on_is_loaded_changed (ActUserManager *manager, + GParamSpec *pspec, + GdmUserChooserWidget *widget) + { +@@ -622,7 +886,7 @@ on_is_loaded_changed (GdmUserManager *manager, + + g_debug ("GdmUserChooserWidget: Users loaded"); + +- users = gdm_user_manager_list_users (manager); ++ users = act_user_manager_list_users (manager); + g_slist_foreach (users, (GFunc) g_object_ref, NULL); + widget->priv->users_to_add = g_slist_concat (widget->priv->users_to_add, g_slist_copy (users)); + +@@ -658,38 +922,7 @@ load_users (GdmUserChooserWidget *widget) + { + + if (widget->priv->show_normal_users) { +- char *temp; +- gboolean res; +- gboolean include_all; +- GSList *includes; +- GSList *excludes; +- +- widget->priv->manager = gdm_user_manager_ref_default (); +- +- /* exclude/include */ +- g_debug ("Setting users to include:"); +- res = gdm_settings_client_get_string (GDM_KEY_INCLUDE, +- &temp); +- parse_string_list (temp, &includes); +- +- g_debug ("Setting users to exclude:"); +- res = gdm_settings_client_get_string (GDM_KEY_EXCLUDE, +- &temp); +- parse_string_list (temp, &excludes); +- +- include_all = FALSE; +- res = gdm_settings_client_get_boolean (GDM_KEY_INCLUDE_ALL, +- &include_all); +- g_object_set (widget->priv->manager, +- "include-all", include_all, +- "include-usernames-list", includes, +- "exclude-usernames-list", excludes, +- NULL); +- +- g_slist_foreach (includes, (GFunc) g_free, NULL); +- g_slist_free (includes); +- g_slist_foreach (excludes, (GFunc) g_free, NULL); +- g_slist_free (excludes); ++ widget->priv->manager = act_user_manager_get_default (); + + g_signal_connect (widget->priv->manager, + "user-added", +@@ -711,7 +944,6 @@ load_users (GdmUserChooserWidget *widget) + "user-changed", + G_CALLBACK (on_user_changed), + widget); +- gdm_user_manager_queue_load (widget->priv->manager); + } else { + gdm_chooser_widget_loaded (GDM_CHOOSER_WIDGET (widget)); + } +diff --git a/gui/simple-greeter/gdm-user-manager.c b/gui/simple-greeter/gdm-user-manager.c +deleted file mode 100644 +index c631989..0000000 +--- a/gui/simple-greeter/gdm-user-manager.c ++++ /dev/null +@@ -1,3082 +0,0 @@ +-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- +- * +- * Copyright (C) 2007-2008 William Jon McCann +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +- * +- */ +- +-#include "config.h" +- +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +- +-#ifdef HAVE_PATHS_H +-#include +-#endif /* HAVE_PATHS_H */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include +-#include +-#include +- +-#include "gdm-user-manager.h" +-#include "gdm-user-private.h" +- +-#define GDM_USER_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerPrivate)) +- +-#define CK_NAME "org.freedesktop.ConsoleKit" +- +-#define CK_MANAGER_PATH "/org/freedesktop/ConsoleKit/Manager" +-#define CK_MANAGER_INTERFACE "org.freedesktop.ConsoleKit.Manager" +-#define CK_SEAT_INTERFACE "org.freedesktop.ConsoleKit.Seat" +-#define CK_SESSION_INTERFACE "org.freedesktop.ConsoleKit.Session" +- +-#define GDM_DBUS_TYPE_G_OBJECT_PATH_ARRAY (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH)) +- +-/* Prefs Defaults */ +- +-#ifdef __sun +-#define FALLBACK_MINIMAL_UID 100 +-#else +-#define FALLBACK_MINIMAL_UID 500 +-#endif +- +-#ifndef _PATH_SHELLS +-#define _PATH_SHELLS "/etc/shells" +-#endif +-#define PATH_PASSWD "/etc/passwd" +- +-#ifndef GDM_USERNAME +-#define GDM_USERNAME "gdm" +-#endif +- +-#define RELOAD_PASSWD_THROTTLE_SECS 5 +- +-/* approximately two months */ +-#define LOGIN_FREQUENCY_TIME_WINDOW_SECS (60 * 24 * 60 * 60) +- +-#define ACCOUNTS_NAME "org.freedesktop.Accounts" +-#define ACCOUNTS_PATH "/org/freedesktop/Accounts" +-#define ACCOUNTS_INTERFACE "org.freedesktop.Accounts" +- +-typedef enum { +- GDM_USER_MANAGER_SEAT_STATE_UNLOADED = 0, +- GDM_USER_MANAGER_SEAT_STATE_GET_SESSION_ID, +- GDM_USER_MANAGER_SEAT_STATE_GET_ID, +- GDM_USER_MANAGER_SEAT_STATE_GET_PROXY, +- GDM_USER_MANAGER_SEAT_STATE_LOADED, +-} GdmUserManagerSeatState; +- +-typedef struct +-{ +- GdmUserManagerSeatState state; +- char *id; +- char *session_id; +- union { +- DBusGProxyCall *get_current_session_call; +- DBusGProxyCall *get_seat_id_call; +- }; +- +- DBusGProxy *proxy; +-} GdmUserManagerSeat; +- +-typedef enum { +- GDM_USER_MANAGER_NEW_SESSION_STATE_UNLOADED = 0, +- GDM_USER_MANAGER_NEW_SESSION_STATE_GET_PROXY, +- GDM_USER_MANAGER_NEW_SESSION_STATE_GET_UID, +- GDM_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY, +- GDM_USER_MANAGER_NEW_SESSION_STATE_MAYBE_ADD, +- GDM_USER_MANAGER_NEW_SESSION_STATE_LOADED, +-} GdmUserManagerNewSessionState; +- +-typedef struct +-{ +- GdmUserManager *manager; +- GdmUserManagerNewSessionState state; +- char *id; +- +- union { +- DBusGProxyCall *get_unix_user_call; +- DBusGProxyCall *get_x11_display_call; +- }; +- +- DBusGProxy *proxy; +- +- uid_t uid; +- char *x11_display; +-} GdmUserManagerNewSession; +- +-typedef enum { +- GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED = 0, +- GDM_USER_MANAGER_GET_USER_STATE_WAIT_FOR_LOADED, +- GDM_USER_MANAGER_GET_USER_STATE_ASK_ACCOUNTS_SERVICE, +- GDM_USER_MANAGER_GET_USER_STATE_FETCHED +-} GdmUserManagerGetUserState; +- +-typedef struct +-{ +- GdmUserManager *manager; +- GdmUserManagerGetUserState state; +- GdmUser *user; +- char *username; +- char *object_path; +- +- DBusGProxyCall *call; +-} GdmUserManagerFetchUserRequest; +- +-struct GdmUserManagerPrivate +-{ +- GHashTable *users_by_name; +- GHashTable *users_by_object_path; +- GHashTable *sessions; +- GHashTable *shells; +- DBusGConnection *connection; +- DBusGProxyCall *get_sessions_call; +- DBusGProxy *accounts_proxy; +- +- GdmUserManagerSeat seat; +- +- GSList *new_sessions; +- GSList *new_users; +- GSList *fetch_user_requests; +- +- GFileMonitor *passwd_monitor; +- GFileMonitor *shells_monitor; +- +- GSList *exclude_usernames; +- GSList *include_usernames; +- gboolean include_all; +- +- gboolean load_passwd_pending; +- +- guint load_id; +- guint reload_passwd_id; +- guint ck_history_id; +- guint ck_history_watchdog_id; +- GPid ck_history_pid; +- +- gboolean is_loaded; +- gboolean has_multiple_users; +- gboolean listing_cached_users; +-}; +- +-enum { +- PROP_0, +- PROP_INCLUDE_ALL, +- PROP_INCLUDE_USERNAMES_LIST, +- PROP_EXCLUDE_USERNAMES_LIST, +- PROP_IS_LOADED, +- PROP_HAS_MULTIPLE_USERS +-}; +- +-enum { +- USER_ADDED, +- USER_REMOVED, +- USER_IS_LOGGED_IN_CHANGED, +- USER_CHANGED, +- LAST_SIGNAL +-}; +- +-static guint signals [LAST_SIGNAL] = { 0, }; +- +-static void gdm_user_manager_class_init (GdmUserManagerClass *klass); +-static void gdm_user_manager_init (GdmUserManager *user_manager); +-static void gdm_user_manager_finalize (GObject *object); +- +-static void load_users_manually (GdmUserManager *manager); +-static void monitor_local_users (GdmUserManager *manager); +-static void load_seat_incrementally (GdmUserManager *manager); +-static void unload_seat (GdmUserManager *manager); +-static void load_users (GdmUserManager *manager); +-static void queue_load_seat_and_users (GdmUserManager *manager); +-static void monitor_local_users (GdmUserManager *manager); +- +-static void load_new_session_incrementally (GdmUserManagerNewSession *new_session); +-static void set_is_loaded (GdmUserManager *manager, gboolean is_loaded); +- +-static void on_new_user_loaded (GdmUser *user, +- GParamSpec *pspec, +- GdmUserManager *manager); +-static void give_up_and_fetch_user_locally (GdmUserManager *manager, +- GdmUserManagerFetchUserRequest *request); +-static void fetch_user_locally (GdmUserManager *manager, +- GdmUser *user, +- const char *username); +-static void fetch_user_incrementally (GdmUserManagerFetchUserRequest *request); +- +-static void maybe_set_is_loaded (GdmUserManager *manager); +-static gpointer user_manager_object = NULL; +- +-G_DEFINE_TYPE (GdmUserManager, gdm_user_manager, G_TYPE_OBJECT) +- +-GQuark +-gdm_user_manager_error_quark (void) +-{ +- static GQuark ret = 0; +- if (ret == 0) { +- ret = g_quark_from_static_string ("gdm_user_manager_error"); +- } +- +- return ret; +-} +- +-static gboolean +-start_new_login_session (GdmUserManager *manager) +-{ +- GError *error; +- gboolean res; +- +- res = g_spawn_command_line_async ("gdmflexiserver -s", &error); +- if (! res) { +- if (error != NULL) { +- g_warning ("Unable to start new login: %s", error->message); +- g_error_free (error); +- } else { +- g_warning ("Unable to start new login"); +- } +- } +- +- return res; +-} +- +-static gboolean +-activate_session_id (GdmUserManager *manager, +- const char *seat_id, +- const char *session_id) +-{ +- DBusError local_error; +- DBusMessage *message; +- DBusMessage *reply; +- gboolean ret; +- +- ret = FALSE; +- reply = NULL; +- +- dbus_error_init (&local_error); +- message = dbus_message_new_method_call ("org.freedesktop.ConsoleKit", +- seat_id, +- "org.freedesktop.ConsoleKit.Seat", +- "ActivateSession"); +- if (message == NULL) { +- goto out; +- } +- +- if (! dbus_message_append_args (message, +- DBUS_TYPE_OBJECT_PATH, &session_id, +- DBUS_TYPE_INVALID)) { +- goto out; +- } +- +- +- dbus_error_init (&local_error); +- reply = dbus_connection_send_with_reply_and_block (dbus_g_connection_get_connection (manager->priv->connection), +- message, +- -1, +- &local_error); +- if (reply == NULL) { +- if (dbus_error_is_set (&local_error)) { +- g_warning ("Unable to activate session: %s", local_error.message); +- dbus_error_free (&local_error); +- goto out; +- } +- } +- +- ret = TRUE; +- out: +- if (message != NULL) { +- dbus_message_unref (message); +- } +- if (reply != NULL) { +- dbus_message_unref (reply); +- } +- +- return ret; +-} +- +-static gboolean +-session_is_login_window (GdmUserManager *manager, +- const char *session_id) +-{ +- DBusGProxy *proxy; +- GError *error; +- gboolean res; +- gboolean ret; +- char *session_type; +- +- ret = FALSE; +- +- proxy = dbus_g_proxy_new_for_name (manager->priv->connection, +- CK_NAME, +- session_id, +- CK_SESSION_INTERFACE); +- if (proxy == NULL) { +- g_warning ("Failed to connect to the ConsoleKit seat object"); +- goto out; +- } +- +- session_type = NULL; +- error = NULL; +- res = dbus_g_proxy_call (proxy, +- "GetSessionType", +- &error, +- G_TYPE_INVALID, +- G_TYPE_STRING, &session_type, +- G_TYPE_INVALID); +- if (! res) { +- if (error != NULL) { +- g_debug ("GdmUserManager: Failed to identify the session type: %s", error->message); +- g_error_free (error); +- } else { +- g_debug ("GdmUserManager: Failed to identify the session type"); +- } +- goto out; +- } +- +- if (session_type == NULL || session_type[0] == '\0' || strcmp (session_type, "LoginWindow") != 0) { +- goto out; +- } +- +- ret = TRUE; +- +- out: +- if (proxy != NULL) { +- g_object_unref (proxy); +- } +- +- return ret; +-} +- +-static char * +-_get_login_window_session_id (GdmUserManager *manager) +-{ +- gboolean res; +- gboolean can_activate_sessions; +- GError *error; +- GPtrArray *sessions; +- char *primary_ssid; +- int i; +- +- if (manager->priv->seat.id == NULL || manager->priv->seat.id[0] == '\0') { +- g_debug ("GdmUserManager: display seat ID is not set; can't switch sessions"); +- return NULL; +- } +- +- primary_ssid = NULL; +- sessions = NULL; +- +- can_activate_sessions = gdm_user_manager_can_switch (manager); +- +- if (! can_activate_sessions) { +- g_debug ("GdmUserManager: seat is unable to activate sessions"); +- goto out; +- } +- +- error = NULL; +- res = dbus_g_proxy_call (manager->priv->seat.proxy, +- "GetSessions", +- &error, +- G_TYPE_INVALID, +- dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &sessions, +- G_TYPE_INVALID); +- if (! res) { +- if (error != NULL) { +- g_warning ("unable to determine sessions for user: %s", +- error->message); +- g_error_free (error); +- } else { +- g_warning ("unable to determine sessions for user"); +- } +- goto out; +- } +- +- for (i = 0; i < sessions->len; i++) { +- char *ssid; +- +- ssid = g_ptr_array_index (sessions, i); +- +- if (session_is_login_window (manager, ssid)) { +- primary_ssid = g_strdup (ssid); +- break; +- } +- } +- g_ptr_array_foreach (sessions, (GFunc)g_free, NULL); +- g_ptr_array_free (sessions, TRUE); +- +- out: +- +- return primary_ssid; +-} +- +-gboolean +-gdm_user_manager_goto_login_session (GdmUserManager *manager) +-{ +- gboolean ret; +- gboolean res; +- char *ssid; +- +- g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), FALSE); +- g_return_val_if_fail (manager->priv->is_loaded, FALSE); +- +- ret = FALSE; +- +- /* First look for any existing LoginWindow sessions on the seat. +- If none are found, create a new one. */ +- +- ssid = _get_login_window_session_id (manager); +- if (ssid != NULL) { +- res = activate_session_id (manager, manager->priv->seat.id, ssid); +- if (res) { +- ret = TRUE; +- } +- } +- +- if (! ret) { +- res = start_new_login_session (manager); +- if (res) { +- ret = TRUE; +- } +- } +- +- return ret; +-} +- +-gboolean +-gdm_user_manager_can_switch (GdmUserManager *manager) +-{ +- gboolean res; +- gboolean can_activate_sessions; +- GError *error; +- +- if (!manager->priv->is_loaded) { +- g_debug ("GdmUserManager: Unable to switch sessions until fully loaded"); +- return FALSE; +- } +- +- if (manager->priv->seat.id == NULL || manager->priv->seat.id[0] == '\0') { +- g_debug ("GdmUserManager: display seat ID is not set; can't switch sessions"); +- return FALSE; +- } +- +- g_debug ("GdmUserManager: checking if seat can activate sessions"); +- +- error = NULL; +- res = dbus_g_proxy_call (manager->priv->seat.proxy, +- "CanActivateSessions", +- &error, +- G_TYPE_INVALID, +- G_TYPE_BOOLEAN, &can_activate_sessions, +- G_TYPE_INVALID); +- if (! res) { +- if (error != NULL) { +- g_warning ("unable to determine if seat can activate sessions: %s", +- error->message); +- g_error_free (error); +- } else { +- g_warning ("unable to determine if seat can activate sessions"); +- } +- return FALSE; +- } +- +- return can_activate_sessions; +-} +- +-gboolean +-gdm_user_manager_activate_user_session (GdmUserManager *manager, +- GdmUser *user) +-{ +- gboolean ret; +- const char *ssid; +- gboolean res; +- +- gboolean can_activate_sessions; +- g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), FALSE); +- g_return_val_if_fail (GDM_IS_USER (user), FALSE); +- g_return_val_if_fail (manager->priv->is_loaded, FALSE); +- +- ret = FALSE; +- +- can_activate_sessions = gdm_user_manager_can_switch (manager); +- +- if (! can_activate_sessions) { +- g_debug ("GdmUserManager: seat is unable to activate sessions"); +- goto out; +- } +- +- ssid = gdm_user_get_primary_session_id (user); +- if (ssid == NULL) { +- goto out; +- } +- +- res = activate_session_id (manager, manager->priv->seat.id, ssid); +- if (! res) { +- g_debug ("GdmUserManager: unable to activate session: %s", ssid); +- goto out; +- } +- +- ret = TRUE; +- out: +- return ret; +-} +- +-static void +-on_user_sessions_changed (GdmUser *user, +- GdmUserManager *manager) +-{ +- guint nsessions; +- +- if (! manager->priv->is_loaded) { +- return; +- } +- +- nsessions = gdm_user_get_num_sessions (user); +- +- g_debug ("GdmUserManager: sessions changed user=%s num=%d", +- gdm_user_get_user_name (user), +- nsessions); +- +- /* only signal on zero and one */ +- if (nsessions > 1) { +- return; +- } +- +- g_signal_emit (manager, signals [USER_IS_LOGGED_IN_CHANGED], 0, user); +-} +- +-static void +-on_user_changed (GdmUser *user, +- GdmUserManager *manager) +-{ +- if (manager->priv->is_loaded) { +- g_debug ("GdmUserManager: user changed"); +- g_signal_emit (manager, signals[USER_CHANGED], 0, user); +- } +-} +- +-static void +-on_get_seat_id_finished (DBusGProxy *proxy, +- DBusGProxyCall *call, +- GdmUserManager *manager) +-{ +- GError *error; +- char *seat_id; +- gboolean res; +- +- g_assert (manager->priv->seat.get_seat_id_call == call); +- +- error = NULL; +- seat_id = NULL; +- res = dbus_g_proxy_end_call (proxy, +- call, +- &error, +- DBUS_TYPE_G_OBJECT_PATH, +- &seat_id, +- G_TYPE_INVALID); +- manager->priv->seat.get_seat_id_call = NULL; +- g_object_unref (proxy); +- +- if (! res) { +- if (error != NULL) { +- g_debug ("Failed to identify the seat of the " +- "current session: %s", +- error->message); +- g_error_free (error); +- } else { +- g_debug ("Failed to identify the seat of the " +- "current session"); +- } +- unload_seat (manager); +- maybe_set_is_loaded (manager); +- return; +- } +- +- g_debug ("GdmUserManager: Found current seat: %s", seat_id); +- +- manager->priv->seat.id = seat_id; +- manager->priv->seat.state++; +- +- load_seat_incrementally (manager); +-} +- +-static void +-get_seat_id_for_current_session (GdmUserManager *manager) +-{ +- DBusGProxy *proxy; +- DBusGProxyCall *call; +- +- proxy = dbus_g_proxy_new_for_name (manager->priv->connection, +- CK_NAME, +- manager->priv->seat.session_id, +- CK_SESSION_INTERFACE); +- if (proxy == NULL) { +- g_warning ("Failed to connect to the ConsoleKit session object"); +- goto failed; +- } +- +- call = dbus_g_proxy_begin_call (proxy, +- "GetSeatId", +- (DBusGProxyCallNotify) +- on_get_seat_id_finished, +- manager, +- NULL, +- G_TYPE_INVALID); +- if (call == NULL) { +- g_warning ("GdmUserManager: failed to make GetSeatId call"); +- goto failed; +- } +- +- manager->priv->seat.get_seat_id_call = call; +- +- return; +- +-failed: +- if (proxy != NULL) { +- g_object_unref (proxy); +- } +- +- unload_seat (manager); +-} +- +-static gint +-match_name_cmpfunc (gconstpointer a, +- gconstpointer b) +-{ +- return g_strcmp0 ((char *) a, +- (char *) b); +-} +- +-static gboolean +-username_in_exclude_list (GdmUserManager *manager, +- const char *username) +-{ +- GSList *found; +- gboolean ret = FALSE; +- +- /* always exclude the "gdm" user. */ +- if (username == NULL || (strcmp (username, GDM_USERNAME) == 0)) { +- return TRUE; +- } +- +- if (manager->priv->exclude_usernames != NULL) { +- found = g_slist_find_custom (manager->priv->exclude_usernames, +- username, +- match_name_cmpfunc); +- if (found != NULL) { +- ret = TRUE; +- } +- } +- +- return ret; +-} +- +-static void +-add_session_for_user (GdmUserManager *manager, +- GdmUser *user, +- const char *ssid) +-{ +- g_hash_table_insert (manager->priv->sessions, +- g_strdup (ssid), +- g_strdup (gdm_user_get_user_name (user))); +- +- _gdm_user_add_session (user, ssid); +- g_debug ("GdmUserManager: added session for user: %s", gdm_user_get_user_name (user)); +-} +- +-static void +-set_has_multiple_users (GdmUserManager *manager, +- gboolean has_multiple_users) +-{ +- if (manager->priv->has_multiple_users != has_multiple_users) { +- manager->priv->has_multiple_users = has_multiple_users; +- g_object_notify (G_OBJECT (manager), "has-multiple-users"); +- } +-} +- +-static GdmUser * +-create_new_user (GdmUserManager *manager) +-{ +- GdmUser *user; +- +- user = g_object_new (GDM_TYPE_USER, NULL); +- +- manager->priv->new_users = g_slist_prepend (manager->priv->new_users, user); +- +- g_signal_connect (user, "notify::is-loaded", G_CALLBACK (on_new_user_loaded), manager); +- +- return g_object_ref (user); +-} +- +-static void +-add_user (GdmUserManager *manager, +- GdmUser *user) +-{ +- const char *object_path; +- +- g_hash_table_insert (manager->priv->users_by_name, +- g_strdup (gdm_user_get_user_name (user)), +- g_object_ref (user)); +- +- object_path = gdm_user_get_object_path (user); +- if (object_path != NULL) { +- g_hash_table_insert (manager->priv->users_by_object_path, +- (gpointer) object_path, +- g_object_ref (user)); +- } +- +- g_signal_connect (user, +- "sessions-changed", +- G_CALLBACK (on_user_sessions_changed), +- manager); +- g_signal_connect (user, +- "changed", +- G_CALLBACK (on_user_changed), +- manager); +- +- if (manager->priv->is_loaded) { +- g_signal_emit (manager, signals[USER_ADDED], 0, user); +- } +- +- if (g_hash_table_size (manager->priv->users_by_name) > 1) { +- set_has_multiple_users (manager, TRUE); +- } +-} +- +-static void +-remove_user (GdmUserManager *manager, +- GdmUser *user) +-{ +- g_object_ref (user); +- +- g_signal_handlers_disconnect_by_func (user, on_user_changed, manager); +- g_signal_handlers_disconnect_by_func (user, on_user_sessions_changed, manager); +- if (gdm_user_get_object_path (user) != NULL) { +- g_hash_table_remove (manager->priv->users_by_object_path, gdm_user_get_object_path (user)); +- } +- g_hash_table_remove (manager->priv->users_by_name, gdm_user_get_user_name (user)); +- +- if (manager->priv->is_loaded) { +- g_signal_emit (manager, signals[USER_REMOVED], 0, user); +- } +- +- g_object_unref (user); +- +- if (g_hash_table_size (manager->priv->users_by_name) > 1) { +- set_has_multiple_users (manager, FALSE); +- } +-} +- +-static void +-on_new_user_loaded (GdmUser *user, +- GParamSpec *pspec, +- GdmUserManager *manager) +-{ +- const char *username; +- GdmUser *old_user; +- +- if (!gdm_user_is_loaded (user)) { +- return; +- } +- +- g_signal_handlers_disconnect_by_func (user, on_new_user_loaded, manager); +- manager->priv->new_users = g_slist_remove (manager->priv->new_users, +- user); +- +- username = gdm_user_get_user_name (user); +- +- if (username == NULL) { +- const char *object_path; +- +- object_path = gdm_user_get_object_path (user); +- +- if (object_path != NULL) { +- g_warning ("GdmUserManager: user has no username " +- "(object path: %s, uid: %lu)", +- object_path, gdm_user_get_uid (user)); +- } else { +- g_warning ("GdmUserManager: user has no username (uid: %lu)", +- gdm_user_get_uid (user)); +- } +- g_object_unref (user); +- return; +- } +- +- if (username_in_exclude_list (manager, username)) { +- g_debug ("GdmUserManager: excluding user '%s'", username); +- g_object_unref (user); +- return; +- } +- +- old_user = g_hash_table_lookup (manager->priv->users_by_name, username); +- +- /* If username got added earlier by a different means, trump it now. +- */ +- if (old_user != NULL) { +- remove_user (manager, old_user); +- } +- +- add_user (manager, user); +- g_object_unref (user); +- +- if (manager->priv->new_users == NULL) { +- set_is_loaded (manager, TRUE); +- } +-} +- +-static GdmUser * +-add_new_user_for_object_path (const char *object_path, +- GdmUserManager *manager) +-{ +- GdmUser *user; +- +- user = g_hash_table_lookup (manager->priv->users_by_object_path, object_path); +- +- if (user != NULL) { +- return user; +- } +- user = create_new_user (manager); +- _gdm_user_update_from_object_path (user, object_path); +- +- return user; +-} +- +-static void +-on_new_user_in_accounts_service (DBusGProxy *proxy, +- const char *object_path, +- gpointer user_data) +-{ +- GdmUserManager *manager = GDM_USER_MANAGER (user_data); +- +- add_new_user_for_object_path (object_path, manager); +-} +- +-static void +-on_user_removed_in_accounts_service (DBusGProxy *proxy, +- const char *object_path, +- gpointer user_data) +-{ +- GdmUserManager *manager = GDM_USER_MANAGER (user_data); +- GdmUser *user; +- +- user = g_hash_table_lookup (manager->priv->users_by_object_path, object_path); +- +- manager->priv->new_users = g_slist_remove (manager->priv->new_users, user); +- +- remove_user (manager, user); +-} +- +-static void +-on_get_current_session_finished (DBusGProxy *proxy, +- DBusGProxyCall *call, +- GdmUserManager *manager) +-{ +- GError *error; +- char *session_id; +- gboolean res; +- +- g_assert (manager->priv->seat.get_current_session_call == call); +- g_assert (manager->priv->seat.state == GDM_USER_MANAGER_SEAT_STATE_GET_SESSION_ID); +- +- error = NULL; +- session_id = NULL; +- res = dbus_g_proxy_end_call (proxy, +- call, +- &error, +- DBUS_TYPE_G_OBJECT_PATH, +- &session_id, +- G_TYPE_INVALID); +- manager->priv->seat.get_current_session_call = NULL; +- g_object_unref (proxy); +- +- if (! res) { +- if (error != NULL) { +- g_debug ("Failed to identify the current session: %s", +- error->message); +- g_error_free (error); +- } else { +- g_debug ("Failed to identify the current session"); +- } +- unload_seat (manager); +- maybe_set_is_loaded (manager); +- return; +- } +- +- manager->priv->seat.session_id = session_id; +- manager->priv->seat.state++; +- +- load_seat_incrementally (manager); +-} +- +-static void +-get_current_session_id (GdmUserManager *manager) +-{ +- DBusGProxy *proxy; +- DBusGProxyCall *call; +- +- proxy = dbus_g_proxy_new_for_name (manager->priv->connection, +- CK_NAME, +- CK_MANAGER_PATH, +- CK_MANAGER_INTERFACE); +- if (proxy == NULL) { +- g_warning ("Failed to connect to the ConsoleKit manager object"); +- goto failed; +- } +- +- call = dbus_g_proxy_begin_call (proxy, +- "GetCurrentSession", +- (DBusGProxyCallNotify) +- on_get_current_session_finished, +- manager, +- NULL, +- G_TYPE_INVALID); +- if (call == NULL) { +- g_warning ("GdmUserManager: failed to make GetCurrentSession call"); +- goto failed; +- } +- +- manager->priv->seat.get_current_session_call = call; +- +- return; +- +-failed: +- if (proxy != NULL) { +- g_object_unref (proxy); +- } +- +- unload_seat (manager); +-} +- +-static void +-unload_new_session (GdmUserManagerNewSession *new_session) +-{ +- GdmUserManager *manager; +- +- manager = new_session->manager; +- +- manager->priv->new_sessions = g_slist_remove (manager->priv->new_sessions, +- new_session); +- +- if (new_session->proxy != NULL) { +- g_object_unref (new_session->proxy); +- } +- +- g_free (new_session->x11_display); +- g_free (new_session->id); +- +- g_slice_free (GdmUserManagerNewSession, new_session); +-} +- +-static void +-get_proxy_for_new_session (GdmUserManagerNewSession *new_session) +-{ +- GdmUserManager *manager; +- DBusGProxy *proxy; +- +- manager = new_session->manager; +- +- proxy = dbus_g_proxy_new_for_name (manager->priv->connection, +- CK_NAME, +- new_session->id, +- CK_SESSION_INTERFACE); +- if (proxy == NULL) { +- g_warning ("Failed to connect to the ConsoleKit '%s' object", +- new_session->id); +- unload_new_session (new_session); +- return; +- } +- +- new_session->proxy = proxy; +- new_session->state++; +- +- load_new_session_incrementally (new_session); +-} +- +-static void +-on_get_unix_user_finished (DBusGProxy *proxy, +- DBusGProxyCall *call, +- GdmUserManagerNewSession *new_session) +-{ +- GdmUserManager *manager; +- GError *error; +- guint uid; +- gboolean res; +- +- manager = new_session->manager; +- +- g_assert (new_session->get_unix_user_call == call); +- +- error = NULL; +- +- uid = (guint) -1; +- res = dbus_g_proxy_end_call (proxy, +- call, +- &error, +- G_TYPE_UINT, &uid, +- G_TYPE_INVALID); +- new_session->get_unix_user_call = NULL; +- +- if (! res) { +- if (error != NULL) { +- g_debug ("Failed to get uid of session '%s': %s", +- new_session->id, error->message); +- g_error_free (error); +- } else { +- g_debug ("Failed to get uid of session '%s'", +- new_session->id); +- } +- unload_new_session (new_session); +- return; +- } +- +- g_debug ("GdmUserManager: Found uid of session '%s': %u", +- new_session->id, uid); +- +- new_session->uid = (uid_t) uid; +- new_session->state++; +- +- load_new_session_incrementally (new_session); +-} +- +-static void +-get_uid_for_new_session (GdmUserManagerNewSession *new_session) +-{ +- DBusGProxyCall *call; +- +- g_assert (new_session->proxy != NULL); +- +- call = dbus_g_proxy_begin_call (new_session->proxy, +- "GetUnixUser", +- (DBusGProxyCallNotify) +- on_get_unix_user_finished, +- new_session, +- NULL, +- G_TYPE_INVALID); +- if (call == NULL) { +- g_warning ("GdmUserManager: failed to make GetUnixUser call"); +- goto failed; +- } +- +- new_session->get_unix_user_call = call; +- return; +- +-failed: +- unload_new_session (new_session); +-} +- +-static void +-on_find_user_by_name_finished (DBusGProxy *proxy, +- DBusGProxyCall *call, +- GdmUserManagerFetchUserRequest *request) +-{ +- GdmUserManager *manager; +- GError *error; +- char *object_path; +- gboolean res; +- +- g_assert (request->call == call); +- +- error = NULL; +- object_path = NULL; +- manager = request->manager; +- res = dbus_g_proxy_end_call (manager->priv->accounts_proxy, +- call, +- &error, +- DBUS_TYPE_G_OBJECT_PATH, +- &object_path, +- G_TYPE_INVALID); +- if (! res) { +- if (error != NULL) { +- g_debug ("GdmUserManager: Failed to find user %s: %s", +- request->username, error->message); +- g_error_free (error); +- } else { +- g_debug ("GdmUserManager: Failed to find user %s", +- request->username); +- } +- give_up_and_fetch_user_locally (manager, request); +- return; +- } +- +- g_debug ("GdmUserManager: Found object path of user '%s': %s", +- request->username, object_path); +- request->object_path = object_path; +- request->state++; +- +- fetch_user_incrementally (request); +-} +- +-static void +-find_user_in_accounts_service (GdmUserManager *manager, +- GdmUserManagerFetchUserRequest *request) +-{ +- DBusGProxyCall *call; +- +- g_debug ("GdmUserManager: Looking for user %s in accounts service", +- request->username); +- +- g_assert (manager->priv->accounts_proxy != NULL); +- +- call = dbus_g_proxy_begin_call (manager->priv->accounts_proxy, +- "FindUserByName", +- (DBusGProxyCallNotify) +- on_find_user_by_name_finished, +- request, +- NULL, +- G_TYPE_STRING, +- request->username, +- G_TYPE_INVALID); +- +- if (call == NULL) { +- g_warning ("GdmUserManager: failed to make FindUserByName('%s') call", +- request->username); +- goto failed; +- } +- +- request->call = call; +- return; +- +-failed: +- give_up_and_fetch_user_locally (manager, request); +-} +- +-static void +-set_is_loaded (GdmUserManager *manager, +- gboolean is_loaded) +-{ +- if (manager->priv->is_loaded != is_loaded) { +- manager->priv->is_loaded = is_loaded; +- g_object_notify (G_OBJECT (manager), "is-loaded"); +- } +-} +- +-static void +-on_list_cached_users_finished (DBusGProxy *proxy, +- DBusGProxyCall *call_id, +- gpointer data) +-{ +- GdmUserManager *manager = data; +- GError *error = NULL; +- GPtrArray *paths; +- +- manager->priv->listing_cached_users = FALSE; +- if (!dbus_g_proxy_end_call (proxy, +- call_id, +- &error, +- dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_OBJECT_PATH), &paths, +- G_TYPE_INVALID)) { +- g_debug ("GdmUserManager: ListCachedUsers failed: %s", error->message); +- g_error_free (error); +- +- g_object_unref (manager->priv->accounts_proxy); +- manager->priv->accounts_proxy = NULL; +- +- load_users_manually (manager); +- +- return; +- } +- +- maybe_set_is_loaded (manager); +- +- g_ptr_array_foreach (paths, (GFunc)add_new_user_for_object_path, manager); +- +- g_ptr_array_foreach (paths, (GFunc)g_free, NULL); +- g_ptr_array_free (paths, TRUE); +- +- /* Add users who are specifically included */ +- if (manager->priv->include_usernames != NULL) { +- GSList *l; +- +- for (l = manager->priv->include_usernames; l != NULL; l = l->next) { +- GdmUser *user; +- +- g_debug ("GdmUserManager: Adding included user %s", (char *)l->data); +- /* +- * The call to gdm_user_manager_get_user will add the user if it is +- * valid and not already in the hash. +- */ +- user = gdm_user_manager_get_user (manager, l->data); +- if (user == NULL) { +- g_debug ("GdmUserManager: unable to lookup user '%s'", (char *)l->data); +- } +- } +- } +-} +- +-static void +-on_get_x11_display_finished (DBusGProxy *proxy, +- DBusGProxyCall *call, +- GdmUserManagerNewSession *new_session) +-{ +- GError *error; +- char *x11_display; +- gboolean res; +- +- g_assert (new_session->get_x11_display_call == call); +- +- error = NULL; +- x11_display = NULL; +- res = dbus_g_proxy_end_call (proxy, +- call, +- &error, +- G_TYPE_STRING, +- &x11_display, +- G_TYPE_INVALID); +- new_session->get_x11_display_call = NULL; +- +- if (! res) { +- if (error != NULL) { +- g_debug ("Failed to get the x11 display of session '%s': %s", +- new_session->id, error->message); +- g_error_free (error); +- } else { +- g_debug ("Failed to get the x11 display of session '%s'", +- new_session->id); +- } +- unload_new_session (new_session); +- return; +- } +- +- g_debug ("GdmUserManager: Found x11 display of session '%s': %s", +- new_session->id, x11_display); +- +- new_session->x11_display = x11_display; +- new_session->state++; +- +- load_new_session_incrementally (new_session); +-} +- +-static void +-get_x11_display_for_new_session (GdmUserManagerNewSession *new_session) +-{ +- DBusGProxyCall *call; +- +- g_assert (new_session->proxy != NULL); +- +- call = dbus_g_proxy_begin_call (new_session->proxy, +- "GetX11Display", +- (DBusGProxyCallNotify) +- on_get_x11_display_finished, +- new_session, +- NULL, +- G_TYPE_INVALID); +- if (call == NULL) { +- g_warning ("GdmUserManager: failed to make GetX11Display call"); +- goto failed; +- } +- +- new_session->get_x11_display_call = call; +- return; +- +-failed: +- unload_new_session (new_session); +-} +- +-static gboolean +-get_pwent_for_name (const char *name, +- struct passwd **pwentp) +-{ +- struct passwd *pwent; +- +- do { +- errno = 0; +- pwent = getpwnam (name); +- } while (pwent == NULL && errno == EINTR); +- +- if (pwentp != NULL) { +- *pwentp = pwent; +- } +- +- return (pwent != NULL); +-} +- +-static gboolean +-get_pwent_for_uid (uid_t uid, +- struct passwd **pwentp) +-{ +- struct passwd *pwent; +- +- do { +- errno = 0; +- pwent = getpwuid (uid); +- } while (pwent == NULL && errno == EINTR); +- +- if (pwentp != NULL) { +- *pwentp = pwent; +- } +- +- return (pwent != NULL); +-} +- +-static void +-maybe_add_new_session (GdmUserManagerNewSession *new_session) +-{ +- GdmUserManager *manager; +- struct passwd *pwent; +- GdmUser *user; +- +- manager = GDM_USER_MANAGER (new_session->manager); +- +- errno = 0; +- get_pwent_for_uid (new_session->uid, &pwent); +- if (pwent == NULL) { +- g_warning ("Unable to lookup user ID %d: %s", +- (int) new_session->uid, g_strerror (errno)); +- goto failed; +- } +- +- /* check exclusions up front */ +- if (username_in_exclude_list (manager, pwent->pw_name)) { +- g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name); +- goto failed; +- } +- +- user = gdm_user_manager_get_user (manager, pwent->pw_name); +- if (user == NULL) { +- return; +- } +- +- add_session_for_user (manager, user, new_session->id); +- +- /* if we haven't yet gotten the login frequency +- then at least add one because the session exists */ +- if (gdm_user_get_login_frequency (user) == 0) { +- _gdm_user_update_login_frequency (user, 1); +- } +- +- manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_LOADED; +- unload_new_session (new_session); +- return; +- +-failed: +- unload_new_session (new_session); +-} +- +-static void +-load_new_session (GdmUserManager *manager, +- const char *session_id) +-{ +- GdmUserManagerNewSession *new_session; +- +- new_session = g_slice_new0 (GdmUserManagerNewSession); +- +- new_session->manager = manager; +- new_session->id = g_strdup (session_id); +- new_session->state = GDM_USER_MANAGER_NEW_SESSION_STATE_UNLOADED + 1; +- +- manager->priv->new_sessions = g_slist_prepend (manager->priv->new_sessions, +- new_session); +- load_new_session_incrementally (new_session); +-} +- +-static void +-seat_session_added (DBusGProxy *seat_proxy, +- const char *session_id, +- GdmUserManager *manager) +-{ +- g_debug ("GdmUserManager: Session added: %s", session_id); +- +- load_new_session (manager, session_id); +-} +- +-static gint +-match_new_session_cmpfunc (gconstpointer a, +- gconstpointer b) +-{ +- GdmUserManagerNewSession *new_session; +- const char *session_id; +- +- new_session = (GdmUserManagerNewSession *) a; +- session_id = (const char *) b; +- +- return strcmp (new_session->id, session_id); +-} +- +-static void +-seat_session_removed (DBusGProxy *seat_proxy, +- const char *session_id, +- GdmUserManager *manager) +-{ +- GdmUser *user; +- GSList *found; +- char *username; +- +- g_debug ("GdmUserManager: Session removed: %s", session_id); +- +- found = g_slist_find_custom (manager->priv->new_sessions, +- session_id, +- match_new_session_cmpfunc); +- +- if (found != NULL) { +- GdmUserManagerNewSession *new_session; +- +- new_session = (GdmUserManagerNewSession *) found->data; +- +- if (new_session->state > GDM_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY) { +- g_debug ("GdmUserManager: New session for uid %d on " +- "x11 display %s removed before fully loading", +- (int) new_session->uid, new_session->x11_display); +- } else if (new_session->state > GDM_USER_MANAGER_NEW_SESSION_STATE_GET_UID) { +- g_debug ("GdmUserManager: New session for uid %d " +- "removed before fully loading", +- (int) new_session->uid); +- } else { +- g_debug ("GdmUserManager: New session removed " +- "before fully loading"); +- } +- unload_new_session (new_session); +- return; +- } +- +- /* since the session object may already be gone +- * we can't query CK directly */ +- +- username = g_hash_table_lookup (manager->priv->sessions, session_id); +- if (username == NULL) { +- return; +- } +- +- user = g_hash_table_lookup (manager->priv->users_by_name, username); +- if (user == NULL) { +- /* nothing to do */ +- return; +- } +- +- g_debug ("GdmUserManager: Session removed for %s", username); +- _gdm_user_remove_session (user, session_id); +-} +- +-static void +-on_seat_proxy_destroy (DBusGProxy *proxy, +- GdmUserManager *manager) +-{ +- g_debug ("GdmUserManager: seat proxy destroyed"); +- +- manager->priv->seat.proxy = NULL; +-} +- +-static void +-get_seat_proxy (GdmUserManager *manager) +-{ +- DBusGProxy *proxy; +- GError *error; +- +- g_assert (manager->priv->seat.proxy == NULL); +- +- error = NULL; +- proxy = dbus_g_proxy_new_for_name_owner (manager->priv->connection, +- CK_NAME, +- manager->priv->seat.id, +- CK_SEAT_INTERFACE, +- &error); +- +- if (proxy == NULL) { +- if (error != NULL) { +- g_warning ("Failed to connect to the ConsoleKit seat object: %s", +- error->message); +- g_error_free (error); +- } else { +- g_warning ("Failed to connect to the ConsoleKit seat object"); +- } +- unload_seat (manager); +- return; +- } +- +- g_signal_connect (proxy, "destroy", G_CALLBACK (on_seat_proxy_destroy), manager); +- +- dbus_g_proxy_add_signal (proxy, +- "SessionAdded", +- DBUS_TYPE_G_OBJECT_PATH, +- G_TYPE_INVALID); +- dbus_g_proxy_add_signal (proxy, +- "SessionRemoved", +- DBUS_TYPE_G_OBJECT_PATH, +- G_TYPE_INVALID); +- dbus_g_proxy_connect_signal (proxy, +- "SessionAdded", +- G_CALLBACK (seat_session_added), +- manager, +- NULL); +- dbus_g_proxy_connect_signal (proxy, +- "SessionRemoved", +- G_CALLBACK (seat_session_removed), +- manager, +- NULL); +- manager->priv->seat.proxy = proxy; +- manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_LOADED; +-} +- +-static void +-unload_seat (GdmUserManager *manager) +-{ +- manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_UNLOADED; +- +- if (manager->priv->seat.proxy != NULL) { +- g_object_unref (manager->priv->seat.proxy); +- manager->priv->seat.proxy = NULL; +- } +- +- g_free (manager->priv->seat.id); +- manager->priv->seat.id = NULL; +- +- g_free (manager->priv->seat.session_id); +- manager->priv->seat.session_id = NULL; +-} +- +-static void +-get_accounts_proxy (GdmUserManager *manager) +-{ +- DBusGProxy *proxy; +- GError *error; +- +- g_assert (manager->priv->accounts_proxy == NULL); +- +- error = NULL; +- proxy = dbus_g_proxy_new_for_name (manager->priv->connection, +- ACCOUNTS_NAME, +- ACCOUNTS_PATH, +- ACCOUNTS_INTERFACE); +- manager->priv->accounts_proxy = proxy; +- +- dbus_g_proxy_add_signal (proxy, +- "UserAdded", +- DBUS_TYPE_G_OBJECT_PATH, +- G_TYPE_INVALID); +- dbus_g_proxy_add_signal (proxy, +- "UserDeleted", +- DBUS_TYPE_G_OBJECT_PATH, +- G_TYPE_INVALID); +- +- dbus_g_proxy_connect_signal (proxy, +- "UserAdded", +- G_CALLBACK (on_new_user_in_accounts_service), +- manager, +- NULL); +- dbus_g_proxy_connect_signal (proxy, +- "UserDeleted", +- G_CALLBACK (on_user_removed_in_accounts_service), +- manager, +- NULL); +-} +- +-static void +-load_new_session_incrementally (GdmUserManagerNewSession *new_session) +-{ +- switch (new_session->state) { +- case GDM_USER_MANAGER_NEW_SESSION_STATE_GET_PROXY: +- get_proxy_for_new_session (new_session); +- break; +- case GDM_USER_MANAGER_NEW_SESSION_STATE_GET_UID: +- get_uid_for_new_session (new_session); +- break; +- case GDM_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY: +- get_x11_display_for_new_session (new_session); +- break; +- case GDM_USER_MANAGER_NEW_SESSION_STATE_MAYBE_ADD: +- maybe_add_new_session (new_session); +- break; +- case GDM_USER_MANAGER_NEW_SESSION_STATE_LOADED: +- break; +- default: +- g_assert_not_reached (); +- } +-} +- +-static void +-free_fetch_user_request (GdmUserManagerFetchUserRequest *request) +-{ +- GdmUserManager *manager; +- +- manager = request->manager; +- +- manager->priv->fetch_user_requests = g_slist_remove (manager->priv->fetch_user_requests, request); +- g_free (request->username); +- g_free (request->object_path); +- g_slice_free (GdmUserManagerFetchUserRequest, request); +-} +- +-static void +-give_up_and_fetch_user_locally (GdmUserManager *manager, +- GdmUserManagerFetchUserRequest *request) +-{ +- +- g_debug ("GdmUserManager: account service unavailable, " +- "fetching user %s locally", +- request->username); +- fetch_user_locally (manager, request->user, request->username); +- request->state = GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED; +-} +- +-static void +-on_user_manager_maybe_ready_for_request (GdmUserManager *manager, +- GParamSpec *pspec, +- GdmUserManagerFetchUserRequest *request) +-{ +- if (!manager->priv->is_loaded) { +- return; +- } +- +- g_signal_handlers_disconnect_by_func (manager, on_user_manager_maybe_ready_for_request, request); +- +- request->state++; +- fetch_user_incrementally (request); +-} +- +-static void +-fetch_user_incrementally (GdmUserManagerFetchUserRequest *request) +-{ +- GdmUserManager *manager; +- +- g_debug ("GdmUserManager: finding user %s state %d", +- request->username, request->state); +- manager = request->manager; +- switch (request->state) { +- case GDM_USER_MANAGER_GET_USER_STATE_WAIT_FOR_LOADED: +- if (manager->priv->is_loaded) { +- request->state++; +- fetch_user_incrementally (request); +- } else { +- g_debug ("GdmUserManager: waiting for user manager to load before finding user %s", +- request->username); +- g_signal_connect (manager, "notify::is-loaded", +- G_CALLBACK (on_user_manager_maybe_ready_for_request), request); +- +- } +- break; +- +- case GDM_USER_MANAGER_GET_USER_STATE_ASK_ACCOUNTS_SERVICE: +- if (manager->priv->accounts_proxy == NULL) { +- give_up_and_fetch_user_locally (manager, request); +- } else { +- find_user_in_accounts_service (manager, request); +- } +- break; +- case GDM_USER_MANAGER_GET_USER_STATE_FETCHED: +- g_debug ("GdmUserManager: user %s fetched", request->username); +- _gdm_user_update_from_object_path (request->user, request->object_path); +- break; +- case GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED: +- g_debug ("GdmUserManager: user %s was not fetched", request->username); +- break; +- default: +- g_assert_not_reached (); +- } +- +- if (request->state == GDM_USER_MANAGER_GET_USER_STATE_FETCHED || +- request->state == GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED) { +- g_debug ("GdmUserManager: finished handling request for user %s", +- request->username); +- free_fetch_user_request (request); +- } +-} +- +-static void +-fetch_user_from_accounts_service (GdmUserManager *manager, +- GdmUser *user, +- const char *username) +-{ +- GdmUserManagerFetchUserRequest *request; +- +- request = g_slice_new0 (GdmUserManagerFetchUserRequest); +- +- request->manager = manager; +- request->username = g_strdup (username); +- request->user = user; +- request->state = GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED + 1; +- +- manager->priv->fetch_user_requests = g_slist_prepend (manager->priv->fetch_user_requests, +- request); +- fetch_user_incrementally (request); +-} +- +-static void +-fetch_user_locally (GdmUserManager *manager, +- GdmUser *user, +- const char *username) +-{ +- struct passwd *pwent; +- +- get_pwent_for_name (username, &pwent); +- +- if (pwent != NULL) { +- _gdm_user_update_from_pwent (user, pwent); +- } +-} +- +-/** +- * gdm_user_manager_get_user: +- * @manager: the manager to query. +- * @username: the login name of the user to get. +- * +- * Retrieves a pointer to the #GdmUser object for the login @username +- * from @manager. Trying to use this object before its +- * #GdmUser:is-loaded property is %TRUE will result in undefined +- * behavior. +- * +- * Returns: (transfer none): #GdmUser object +- **/ +-GdmUser * +-gdm_user_manager_get_user (GdmUserManager *manager, +- const char *username) +-{ +- GdmUser *user; +- +- g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL); +- g_return_val_if_fail (username != NULL && username[0] != '\0', NULL); +- +- user = g_hash_table_lookup (manager->priv->users_by_name, username); +- +- /* if we don't have it loaded try to load it now */ +- if (user == NULL) { +- user = create_new_user (manager); +- +- if (manager->priv->accounts_proxy != NULL) { +- fetch_user_from_accounts_service (manager, user, username); +- } else { +- fetch_user_locally (manager, user, username); +- } +- } +- +- return user; +-} +- +-/** +- * gdm_user_manager_get_user_by_uid: +- * @manager: the manager to query. +- * @uid: the uid of the user to get. +- * +- * Retrieves a pointer to the #GdmUser object for the uid @uid +- * from @manager. Trying to use this object before its +- * #GdmUser:is-loaded property is %TRUE will result in undefined +- * behavior. +- * +- * Returns: (transfer none): #GdmUser object +- */ +-GdmUser * +-gdm_user_manager_get_user_by_uid (GdmUserManager *manager, +- gulong uid) +-{ +- struct passwd *pwent; +- +- g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL); +- +- get_pwent_for_uid (uid, &pwent); +- if (pwent == NULL) { +- g_warning ("GdmUserManager: unable to lookup uid %d", (int)uid); +- return NULL; +- } +- +- return gdm_user_manager_get_user (manager, pwent->pw_name); +-} +- +-static void +-listify_hash_values_hfunc (gpointer key, +- gpointer value, +- gpointer user_data) +-{ +- GSList **list = user_data; +- +- *list = g_slist_prepend (*list, value); +-} +- +-/** +- * gdm_user_manager_list_users: +- * @manager: a #GdmUserManager +- * +- * Get a list of system user accounts +- * +- * Returns: (element-type GdmUser) (transfer full): List of #GdmUser objects +- */ +-GSList * +-gdm_user_manager_list_users (GdmUserManager *manager) +-{ +- GSList *retval; +- +- g_return_val_if_fail (GDM_IS_USER_MANAGER (manager), NULL); +- +- retval = NULL; +- g_hash_table_foreach (manager->priv->users_by_name, listify_hash_values_hfunc, &retval); +- +- return g_slist_sort (retval, (GCompareFunc) gdm_user_collate); +-} +- +-static gboolean +-parse_value_as_ulong (const char *value, +- gulong *ulongval) +-{ +- char *end_of_valid_long; +- glong long_value; +- gulong ulong_value; +- +- errno = 0; +- long_value = strtol (value, &end_of_valid_long, 10); +- +- if (*value == '\0' || *end_of_valid_long != '\0') { +- return FALSE; +- } +- +- ulong_value = long_value; +- if (ulong_value != long_value || errno == ERANGE) { +- return FALSE; +- } +- +- *ulongval = ulong_value; +- +- return TRUE; +-} +- +-static gboolean +-parse_ck_history_line (const char *line, +- char **user_namep, +- gulong *frequencyp) +-{ +- GRegex *re; +- GMatchInfo *match_info; +- gboolean res; +- gboolean ret; +- GError *error; +- +- ret = FALSE; +- re = NULL; +- match_info = NULL; +- +- error = NULL; +- re = g_regex_new ("(?P[0-9a-zA-Z]+)[ ]+(?P[0-9]+)", 0, 0, &error); +- if (re == NULL) { +- if (error != NULL) { +- g_critical ("%s", error->message); +- } else { +- g_critical ("Error in regex call"); +- } +- goto out; +- } +- +- g_regex_match (re, line, 0, &match_info); +- +- res = g_match_info_matches (match_info); +- if (! res) { +- g_warning ("Unable to parse history: %s", line); +- goto out; +- } +- +- if (user_namep != NULL) { +- *user_namep = g_match_info_fetch_named (match_info, "username"); +- } +- +- if (frequencyp != NULL) { +- char *freq; +- freq = g_match_info_fetch_named (match_info, "frequency"); +- res = parse_value_as_ulong (freq, frequencyp); +- g_free (freq); +- if (! res) { +- goto out; +- } +- } +- +- ret = TRUE; +- +- out: +- if (match_info != NULL) { +- g_match_info_free (match_info); +- } +- if (re != NULL) { +- g_regex_unref (re); +- } +- return ret; +-} +- +-static void +-process_ck_history_line (GdmUserManager *manager, +- const char *line) +-{ +- gboolean res; +- char *username; +- gulong frequency; +- GdmUser *user; +- +- frequency = 0; +- username = NULL; +- res = parse_ck_history_line (line, &username, &frequency); +- if (! res) { +- return; +- } +- +- if (username_in_exclude_list (manager, username)) { +- g_debug ("GdmUserManager: excluding user '%s'", username); +- g_free (username); +- return; +- } +- +- user = gdm_user_manager_get_user (manager, username); +- if (user == NULL) { +- g_debug ("GdmUserManager: unable to lookup user '%s'", username); +- g_free (username); +- return; +- } +- +- _gdm_user_update_login_frequency (user, frequency); +- g_free (username); +-} +- +-static void +-maybe_set_is_loaded (GdmUserManager *manager) +-{ +- if (manager->priv->is_loaded) { +- return; +- } +- +- if (manager->priv->ck_history_pid != 0) { +- return; +- } +- +- if (manager->priv->load_passwd_pending) { +- return; +- } +- +- if (manager->priv->get_sessions_call != NULL) { +- return; +- } +- +- if (manager->priv->listing_cached_users) { +- return; +- } +- +- /* Don't set is_loaded yet unless the seat is already loaded +- * or failed to load. +- */ +- if (manager->priv->seat.state != GDM_USER_MANAGER_SEAT_STATE_LOADED +- && manager->priv->seat.state != GDM_USER_MANAGER_SEAT_STATE_UNLOADED) { +- return; +- } +- +- set_is_loaded (manager, TRUE); +-} +- +-static gboolean +-ck_history_watch (GIOChannel *source, +- GIOCondition condition, +- GdmUserManager *manager) +-{ +- GIOStatus status; +- gboolean done = FALSE; +- +- g_return_val_if_fail (manager != NULL, FALSE); +- +- if (condition & G_IO_IN) { +- char *str; +- GError *error; +- +- error = NULL; +- status = g_io_channel_read_line (source, &str, NULL, NULL, &error); +- if (error != NULL) { +- g_warning ("GdmUserManager: unable to read line: %s", error->message); +- g_error_free (error); +- } +- +- if (status == G_IO_STATUS_NORMAL) { +- g_debug ("GdmUserManager: history output: %s", str); +- process_ck_history_line (manager, str); +- } else if (status == G_IO_STATUS_EOF) { +- done = TRUE; +- } +- +- g_free (str); +- } else if (condition & G_IO_HUP) { +- done = TRUE; +- } +- +- if (done) { +- manager->priv->ck_history_id = 0; +- if (manager->priv->ck_history_watchdog_id != 0) { +- g_source_remove (manager->priv->ck_history_watchdog_id); +- manager->priv->ck_history_watchdog_id = 0; +- } +- manager->priv->ck_history_pid = 0; +- +- maybe_set_is_loaded (manager); +- +- return FALSE; +- } +- +- return TRUE; +-} +- +-static int +-signal_pid (int pid, +- int signal) +-{ +- int status = -1; +- +- status = kill (pid, signal); +- +- if (status < 0) { +- if (errno == ESRCH) { +- g_debug ("Child process %lu was already dead.", +- (unsigned long) pid); +- } else { +- char buf [1024]; +- snprintf (buf, +- sizeof (buf), +- "Couldn't kill child process %lu", +- (unsigned long) pid); +- perror (buf); +- } +- } +- +- return status; +-} +- +-static gboolean +-ck_history_watchdog (GdmUserManager *manager) +-{ +- if (manager->priv->ck_history_pid > 0) { +- g_debug ("Killing ck-history process"); +- signal_pid (manager->priv->ck_history_pid, SIGTERM); +- manager->priv->ck_history_pid = 0; +- } +- +- manager->priv->ck_history_watchdog_id = 0; +- return FALSE; +-} +- +-static gboolean +-load_ck_history (GdmUserManager *manager) +-{ +- char *command; +- char *since; +- const char *seat_id; +- GError *error; +- gboolean res; +- char **argv; +- int standard_out; +- GIOChannel *channel; +- GTimeVal tv; +- +- g_assert (manager->priv->ck_history_id == 0); +- +- command = NULL; +- +- seat_id = NULL; +- if (manager->priv->seat.id != NULL +- && g_str_has_prefix (manager->priv->seat.id, "/org/freedesktop/ConsoleKit/")) { +- +- seat_id = manager->priv->seat.id + strlen ("/org/freedesktop/ConsoleKit/"); +- } +- +- if (seat_id == NULL) { +- g_warning ("Unable to load CK history: no seat-id found"); +- goto out; +- } +- +- g_get_current_time (&tv); +- tv.tv_sec -= LOGIN_FREQUENCY_TIME_WINDOW_SECS; +- since = g_time_val_to_iso8601 (&tv); +- +- command = g_strdup_printf ("ck-history --frequent --since='%s' --seat='%s' --session-type=''", +- since, +- seat_id); +- g_free (since); +- g_debug ("GdmUserManager: running '%s'", command); +- error = NULL; +- if (! g_shell_parse_argv (command, NULL, &argv, &error)) { +- if (error != NULL) { +- g_warning ("Could not parse command: %s", error->message); +- g_error_free (error); +- } else { +- g_warning ("Could not parse command"); +- } +- goto out; +- } +- +- error = NULL; +- res = g_spawn_async_with_pipes (NULL, +- argv, +- NULL, +- G_SPAWN_SEARCH_PATH, +- NULL, +- NULL, +- &manager->priv->ck_history_pid, /* pid */ +- NULL, +- &standard_out, +- NULL, +- &error); +- g_strfreev (argv); +- if (! res) { +- if (error != NULL) { +- g_warning ("Unable to run ck-history: %s", error->message); +- g_error_free (error); +- } else { +- g_warning ("Unable to run ck-history"); +- } +- goto out; +- } +- +- channel = g_io_channel_unix_new (standard_out); +- g_io_channel_set_close_on_unref (channel, TRUE); +- g_io_channel_set_flags (channel, +- g_io_channel_get_flags (channel) | G_IO_FLAG_NONBLOCK, +- NULL); +- manager->priv->ck_history_watchdog_id = g_timeout_add_seconds (1, (GSourceFunc) ck_history_watchdog, manager); +- manager->priv->ck_history_id = g_io_add_watch (channel, +- G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, +- (GIOFunc)ck_history_watch, +- manager); +- g_io_channel_unref (channel); +- +- out: +- +- g_free (command); +- +- return manager->priv->ck_history_id != 0; +-} +- +-static void +-reload_passwd_file (GHashTable *valid_shells, +- GSList *exclude_users, +- GSList *include_users, +- gboolean include_all, +- GHashTable *current_users_by_name, +- GSList **added_users, +- GSList **removed_users) +-{ +- FILE *fp; +- GHashTableIter iter; +- GHashTable *new_users_by_name; +- GdmUser *user; +- char *name; +- +- new_users_by_name = g_hash_table_new_full (g_str_hash, +- g_str_equal, +- NULL, +- g_object_unref); +- +- errno = 0; +- fp = fopen (PATH_PASSWD, "r"); +- if (fp == NULL) { +- g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno)); +- goto out; +- } +- +- /* Make sure we keep users who are logged in no matter what. */ +- g_hash_table_iter_init (&iter, current_users_by_name); +- while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &user)) { +- struct passwd *pwent; +- +- get_pwent_for_name (name, &pwent); +- if (pwent == NULL) { +- continue; +- } +- +- g_object_freeze_notify (G_OBJECT (user)); +- _gdm_user_update_from_pwent (user, pwent); +- g_hash_table_insert (new_users_by_name, (char *)gdm_user_get_user_name (user), g_object_ref (user)); +- } +- +- if (include_users != NULL) { +- GSList *l; +- for (l = include_users; l != NULL; l = l->next) { +- struct passwd *pwent; +- +- get_pwent_for_name (l->data, &pwent); +- if (pwent == NULL) { +- continue; +- } +- +- user = g_hash_table_lookup (new_users_by_name, pwent->pw_name); +- if (user != NULL) { +- /* already there */ +- continue; +- } +- +- user = g_hash_table_lookup (current_users_by_name, pwent->pw_name); +- if (user == NULL) { +- user = g_object_new (GDM_TYPE_USER, NULL); +- } else { +- g_object_ref (user); +- } +- g_object_freeze_notify (G_OBJECT (user)); +- _gdm_user_update_from_pwent (user, pwent); +- g_hash_table_insert (new_users_by_name, (char *)gdm_user_get_user_name (user), user); +- } +- } +- +- if (include_all != TRUE) { +- g_debug ("GdmUserManager: include_all is FALSE"); +- } else { +- struct passwd *pwent; +- +- g_debug ("GdmUserManager: include_all is TRUE"); +- +- for (pwent = fgetpwent (fp); +- pwent != NULL; +- pwent = fgetpwent (fp)) { +- +- /* Skip users below MinimalUID... */ +- if (pwent->pw_uid < FALLBACK_MINIMAL_UID) { +- continue; +- } +- +- /* ...And users w/ invalid shells... */ +- if (pwent->pw_shell == NULL +- || !g_hash_table_lookup (valid_shells, pwent->pw_shell)) { +- g_debug ("GdmUserManager: skipping user with bad shell: %s", pwent->pw_name); +- continue; +- } +- +- /* always exclude the "gdm" user. */ +- if (strcmp (pwent->pw_name, GDM_USERNAME) == 0) { +- continue; +- } +- +- /* ...And explicitly excluded users */ +- if (exclude_users != NULL) { +- GSList *found; +- +- found = g_slist_find_custom (exclude_users, +- pwent->pw_name, +- match_name_cmpfunc); +- if (found != NULL) { +- g_debug ("GdmUserManager: explicitly skipping user: %s", pwent->pw_name); +- continue; +- } +- } +- +- user = g_hash_table_lookup (new_users_by_name, pwent->pw_name); +- if (user != NULL) { +- /* already there */ +- continue; +- } +- +- user = g_hash_table_lookup (current_users_by_name, pwent->pw_name); +- if (user == NULL) { +- user = g_object_new (GDM_TYPE_USER, NULL); +- } else { +- g_object_ref (user); +- } +- +- /* Freeze & update users not already in the new list */ +- g_object_freeze_notify (G_OBJECT (user)); +- _gdm_user_update_from_pwent (user, pwent); +- g_hash_table_insert (new_users_by_name, (char *)gdm_user_get_user_name (user), user); +- } +- } +- +- /* Go through and handle added users */ +- g_hash_table_iter_init (&iter, new_users_by_name); +- while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &user)) { +- GdmUser *user2; +- user2 = g_hash_table_lookup (current_users_by_name, name); +- if (user2 == NULL) { +- *added_users = g_slist_prepend (*added_users, g_object_ref (user)); +- } +- } +- +- /* Go through and handle removed users */ +- g_hash_table_iter_init (&iter, current_users_by_name); +- while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &user)) { +- GdmUser *user2; +- user2 = g_hash_table_lookup (new_users_by_name, name); +- if (user2 == NULL) { +- *removed_users = g_slist_prepend (*removed_users, g_object_ref (user)); +- } +- } +- +- out: +- /* Cleanup */ +- +- fclose (fp); +- +- g_hash_table_iter_init (&iter, new_users_by_name); +- while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &user)) { +- g_object_thaw_notify (G_OBJECT (user)); +- } +- +- g_hash_table_destroy (new_users_by_name); +-} +- +-typedef struct { +- GdmUserManager *manager; +- GSList *exclude_users; +- GSList *include_users; +- gboolean include_all; +- GHashTable *shells; +- GHashTable *current_users_by_name; +- GSList *added_users; +- GSList *removed_users; +-} PasswdData; +- +-static void +-passwd_data_free (PasswdData *data) +-{ +- if (data->manager != NULL) { +- g_object_unref (data->manager); +- } +- +- g_slist_foreach (data->added_users, (GFunc) g_object_unref, NULL); +- g_slist_free (data->added_users); +- +- g_slist_foreach (data->removed_users, (GFunc) g_object_unref, NULL); +- g_slist_free (data->removed_users); +- +- g_slist_foreach (data->exclude_users, (GFunc) g_free, NULL); +- g_slist_free (data->exclude_users); +- +- g_slist_foreach (data->include_users, (GFunc) g_free, NULL); +- g_slist_free (data->include_users); +- +- g_slice_free (PasswdData, data); +-} +- +-static gboolean +-reload_passwd_job_done (PasswdData *data) +-{ +- GSList *l; +- +- g_debug ("GdmUserManager: done reloading passwd file"); +- +- /* Go through and handle added users */ +- for (l = data->added_users; l != NULL; l = l->next) { +- add_user (data->manager, l->data); +- } +- +- /* Go through and handle removed users */ +- for (l = data->removed_users; l != NULL; l = l->next) { +- remove_user (data->manager, l->data); +- } +- +- data->manager->priv->load_passwd_pending = FALSE; +- +- if (! data->manager->priv->is_loaded) { +- maybe_set_is_loaded (data->manager); +- +- if (data->manager->priv->include_all == TRUE) { +- monitor_local_users (data->manager); +- } +- } +- +- passwd_data_free (data); +- +- return FALSE; +-} +- +-static gboolean +-do_reload_passwd_job (GIOSchedulerJob *job, +- GCancellable *cancellable, +- PasswdData *data) +-{ +- g_debug ("GdmUserManager: reloading passwd file worker"); +- +- reload_passwd_file (data->shells, +- data->exclude_users, +- data->include_users, +- data->include_all, +- data->current_users_by_name, +- &data->added_users, +- &data->removed_users); +- +- g_io_scheduler_job_send_to_mainloop_async (job, +- (GSourceFunc) reload_passwd_job_done, +- data, +- NULL); +- +- return FALSE; +-} +- +-static GSList * +-slist_deep_copy (const GSList *list) +-{ +- GSList *retval; +- GSList *l; +- +- if (list == NULL) +- return NULL; +- +- retval = g_slist_copy ((GSList *) list); +- for (l = retval; l != NULL; l = l->next) { +- l->data = g_strdup (l->data); +- } +- +- return retval; +-} +- +-static void +-schedule_reload_passwd (GdmUserManager *manager) +-{ +- PasswdData *passwd_data; +- +- manager->priv->load_passwd_pending = TRUE; +- +- passwd_data = g_slice_new0 (PasswdData); +- passwd_data->manager = g_object_ref (manager); +- passwd_data->shells = manager->priv->shells; +- passwd_data->exclude_users = slist_deep_copy (manager->priv->exclude_usernames); +- passwd_data->include_users = slist_deep_copy (manager->priv->include_usernames); +- passwd_data->include_all = manager->priv->include_all; +- passwd_data->current_users_by_name = manager->priv->users_by_name; +- passwd_data->added_users = NULL; +- passwd_data->removed_users = NULL; +- +- g_debug ("GdmUserManager: scheduling a passwd file update"); +- +- g_io_scheduler_push_job ((GIOSchedulerJobFunc) do_reload_passwd_job, +- passwd_data, +- NULL, +- G_PRIORITY_DEFAULT, +- NULL); +-} +- +-static void +-load_sessions_from_array (GdmUserManager *manager, +- const char * const *session_ids, +- int number_of_sessions) +-{ +- int i; +- +- for (i = 0; i < number_of_sessions; i++) { +- load_new_session (manager, session_ids[i]); +- } +-} +- +-static void +-on_get_sessions_finished (DBusGProxy *proxy, +- DBusGProxyCall *call, +- GdmUserManager *manager) +-{ +- GError *error; +- gboolean res; +- GPtrArray *sessions; +- +- g_assert (manager->priv->get_sessions_call == call); +- +- error = NULL; +- sessions = NULL; +- res = dbus_g_proxy_end_call (proxy, +- call, +- &error, +- GDM_DBUS_TYPE_G_OBJECT_PATH_ARRAY, +- &sessions, +- G_TYPE_INVALID); +- +- if (! res) { +- if (error != NULL) { +- g_warning ("unable to determine sessions for seat: %s", +- error->message); +- g_error_free (error); +- } else { +- g_warning ("unable to determine sessions for seat"); +- } +- return; +- } +- +- manager->priv->get_sessions_call = NULL; +- g_assert (sessions->len <= G_MAXINT); +- load_sessions_from_array (manager, +- (const char * const *) sessions->pdata, +- (int) sessions->len); +- g_ptr_array_foreach (sessions, (GFunc) g_free, NULL); +- g_ptr_array_free (sessions, TRUE); +- maybe_set_is_loaded (manager); +-} +- +-static void +-load_sessions (GdmUserManager *manager) +-{ +- DBusGProxyCall *call; +- +- if (manager->priv->seat.proxy == NULL) { +- g_debug ("GdmUserManager: no seat proxy; can't load sessions"); +- return; +- } +- +- call = dbus_g_proxy_begin_call (manager->priv->seat.proxy, +- "GetSessions", +- (DBusGProxyCallNotify) +- on_get_sessions_finished, +- manager, +- NULL, +- G_TYPE_INVALID); +- +- if (call == NULL) { +- g_warning ("GdmUserManager: failed to make GetSessions call"); +- return; +- } +- +- manager->priv->get_sessions_call = call; +-} +- +-static void +-reload_shells (GdmUserManager *manager) +-{ +- char *shell; +- +- setusershell (); +- +- g_hash_table_remove_all (manager->priv->shells); +- for (shell = getusershell (); shell != NULL; shell = getusershell ()) { +- /* skip well known not-real shells */ +- if (shell == NULL +- || strcmp (shell, "/sbin/nologin") == 0 +- || strcmp (shell, "/bin/false") == 0) { +- g_debug ("GdmUserManager: skipping shell %s", shell); +- continue; +- } +- g_hash_table_insert (manager->priv->shells, +- g_strdup (shell), +- GUINT_TO_POINTER (TRUE)); +- } +- +- endusershell (); +-} +- +-static void +-load_users_manually (GdmUserManager *manager) +-{ +- gboolean res; +- +- manager->priv->shells = g_hash_table_new_full (g_str_hash, +- g_str_equal, +- g_free, +- NULL); +- reload_shells (manager); +- +- load_sessions (manager); +- +- res = load_ck_history (manager); +- schedule_reload_passwd (manager); +-} +- +-static void +-load_users (GdmUserManager *manager) +-{ +- g_assert (manager->priv->accounts_proxy != NULL); +- g_debug ("GdmUserManager: calling 'ListCachedUsers'"); +- +- dbus_g_proxy_begin_call (manager->priv->accounts_proxy, +- "ListCachedUsers", +- on_list_cached_users_finished, +- manager, +- NULL, +- G_TYPE_INVALID); +- manager->priv->listing_cached_users = TRUE; +-} +- +-static void +-load_seat_incrementally (GdmUserManager *manager) +-{ +- g_assert (manager->priv->seat.proxy == NULL); +- +- switch (manager->priv->seat.state) { +- case GDM_USER_MANAGER_SEAT_STATE_GET_SESSION_ID: +- get_current_session_id (manager); +- break; +- case GDM_USER_MANAGER_SEAT_STATE_GET_ID: +- get_seat_id_for_current_session (manager); +- break; +- case GDM_USER_MANAGER_SEAT_STATE_GET_PROXY: +- get_seat_proxy (manager); +- break; +- case GDM_USER_MANAGER_SEAT_STATE_LOADED: +- break; +- default: +- g_assert_not_reached (); +- } +- +- if (manager->priv->seat.state == GDM_USER_MANAGER_SEAT_STATE_LOADED) { +- gboolean res; +- +- load_sessions (manager); +- res = load_ck_history (manager); +- } +- +- maybe_set_is_loaded (manager); +-} +- +-static gboolean +-load_idle (GdmUserManager *manager) +-{ +- manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_UNLOADED + 1; +- load_seat_incrementally (manager); +- load_users (manager); +- manager->priv->load_id = 0; +- +- return FALSE; +-} +- +-static void +-queue_load_seat_and_users (GdmUserManager *manager) +-{ +- if (manager->priv->load_id > 0) { +- return; +- } +- +- manager->priv->load_id = g_idle_add ((GSourceFunc)load_idle, manager); +-} +- +-static gboolean +-reload_passwd_idle (GdmUserManager *manager) +-{ +- schedule_reload_passwd (manager); +- manager->priv->reload_passwd_id = 0; +- +- return FALSE; +-} +- +-static void +-queue_reload_passwd (GdmUserManager *manager) +-{ +- if (manager->priv->reload_passwd_id > 0) { +- g_source_remove (manager->priv->reload_passwd_id); +- } +- +- manager->priv->reload_passwd_id = g_timeout_add_seconds (RELOAD_PASSWD_THROTTLE_SECS, (GSourceFunc)reload_passwd_idle, manager); +-} +- +-static void +-on_shells_monitor_changed (GFileMonitor *monitor, +- GFile *file, +- GFile *other_file, +- GFileMonitorEvent event_type, +- GdmUserManager *manager) +-{ +- if (event_type != G_FILE_MONITOR_EVENT_CHANGED && +- event_type != G_FILE_MONITOR_EVENT_CREATED) { +- return; +- } +- +- reload_shells (manager); +- queue_reload_passwd (manager); +-} +- +-static void +-on_passwd_monitor_changed (GFileMonitor *monitor, +- GFile *file, +- GFile *other_file, +- GFileMonitorEvent event_type, +- GdmUserManager *manager) +-{ +- if (event_type != G_FILE_MONITOR_EVENT_CHANGED && +- event_type != G_FILE_MONITOR_EVENT_CREATED) { +- return; +- } +- +- queue_reload_passwd (manager); +-} +- +-static void +-gdm_user_manager_get_property (GObject *object, +- guint prop_id, +- GValue *value, +- GParamSpec *pspec) +-{ +- GdmUserManager *manager; +- +- manager = GDM_USER_MANAGER (object); +- +- switch (prop_id) { +- case PROP_IS_LOADED: +- g_value_set_boolean (value, manager->priv->is_loaded); +- break; +- case PROP_HAS_MULTIPLE_USERS: +- g_value_set_boolean (value, manager->priv->has_multiple_users); +- break; +- case PROP_INCLUDE_ALL: +- g_value_set_boolean (value, manager->priv->include_all); +- break; +- case PROP_INCLUDE_USERNAMES_LIST: +- g_value_set_pointer (value, manager->priv->include_usernames); +- break; +- case PROP_EXCLUDE_USERNAMES_LIST: +- g_value_set_pointer (value, manager->priv->exclude_usernames); +- break; +- default: +- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +- break; +- } +-} +- +-static void +-set_include_usernames (GdmUserManager *manager, +- GSList *list) +-{ +- if (manager->priv->include_usernames != NULL) { +- g_slist_foreach (manager->priv->include_usernames, (GFunc) g_free, NULL); +- g_slist_free (manager->priv->include_usernames); +- } +- manager->priv->include_usernames = slist_deep_copy (list); +-} +- +-static void +-set_exclude_usernames (GdmUserManager *manager, +- GSList *list) +-{ +- if (manager->priv->exclude_usernames != NULL) { +- g_slist_foreach (manager->priv->exclude_usernames, (GFunc) g_free, NULL); +- g_slist_free (manager->priv->exclude_usernames); +- } +- manager->priv->exclude_usernames = slist_deep_copy (list); +-} +- +-static void +-set_include_all (GdmUserManager *manager, +- gboolean all) +-{ +- if (manager->priv->include_all != all) { +- manager->priv->include_all = all; +- } +-} +- +-static void +-gdm_user_manager_set_property (GObject *object, +- guint prop_id, +- const GValue *value, +- GParamSpec *pspec) +-{ +- GdmUserManager *self; +- +- self = GDM_USER_MANAGER (object); +- +- switch (prop_id) { +- case PROP_INCLUDE_ALL: +- set_include_all (self, g_value_get_boolean (value)); +- break; +- case PROP_INCLUDE_USERNAMES_LIST: +- set_include_usernames (self, g_value_get_pointer (value)); +- break; +- case PROP_EXCLUDE_USERNAMES_LIST: +- set_exclude_usernames (self, g_value_get_pointer (value)); +- break; +- default: +- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); +- break; +- } +-} +- +-static void +-monitor_local_users (GdmUserManager *manager) +-{ +- GFile *file; +- GError *error; +- +- g_debug ("GdmUserManager: Monitoring local users"); +- +- /* /etc/shells */ +- file = g_file_new_for_path (_PATH_SHELLS); +- error = NULL; +- manager->priv->shells_monitor = g_file_monitor_file (file, +- G_FILE_MONITOR_NONE, +- NULL, +- &error); +- if (manager->priv->shells_monitor != NULL) { +- g_signal_connect (manager->priv->shells_monitor, +- "changed", +- G_CALLBACK (on_shells_monitor_changed), +- manager); +- } else { +- g_warning ("Unable to monitor %s: %s", _PATH_SHELLS, error->message); +- g_error_free (error); +- } +- g_object_unref (file); +- +- /* /etc/passwd */ +- file = g_file_new_for_path (PATH_PASSWD); +- manager->priv->passwd_monitor = g_file_monitor_file (file, +- G_FILE_MONITOR_NONE, +- NULL, +- &error); +- if (manager->priv->passwd_monitor != NULL) { +- g_signal_connect (manager->priv->passwd_monitor, +- "changed", +- G_CALLBACK (on_passwd_monitor_changed), +- manager); +- } else { +- g_warning ("Unable to monitor %s: %s", PATH_PASSWD, error->message); +- g_error_free (error); +- } +- g_object_unref (file); +-} +- +-static void +-gdm_user_manager_class_init (GdmUserManagerClass *klass) +-{ +- GObjectClass *object_class = G_OBJECT_CLASS (klass); +- +- object_class->finalize = gdm_user_manager_finalize; +- object_class->get_property = gdm_user_manager_get_property; +- object_class->set_property = gdm_user_manager_set_property; +- +- g_object_class_install_property (object_class, +- PROP_IS_LOADED, +- g_param_spec_boolean ("is-loaded", +- NULL, +- NULL, +- FALSE, +- G_PARAM_READABLE)); +- g_object_class_install_property (object_class, +- PROP_HAS_MULTIPLE_USERS, +- g_param_spec_boolean ("has-multiple-users", +- NULL, +- NULL, +- FALSE, +- G_PARAM_READABLE)); +- g_object_class_install_property (object_class, +- PROP_INCLUDE_ALL, +- g_param_spec_boolean ("include-all", +- NULL, +- NULL, +- FALSE, +- G_PARAM_READWRITE)); +- g_object_class_install_property (object_class, +- PROP_INCLUDE_USERNAMES_LIST, +- g_param_spec_pointer ("include-usernames-list", +- NULL, +- NULL, +- G_PARAM_READWRITE)); +- +- g_object_class_install_property (object_class, +- PROP_EXCLUDE_USERNAMES_LIST, +- g_param_spec_pointer ("exclude-usernames-list", +- NULL, +- NULL, +- G_PARAM_READWRITE)); +- +- signals [USER_ADDED] = +- g_signal_new ("user-added", +- G_TYPE_FROM_CLASS (klass), +- G_SIGNAL_RUN_LAST, +- G_STRUCT_OFFSET (GdmUserManagerClass, user_added), +- NULL, NULL, +- g_cclosure_marshal_VOID__OBJECT, +- G_TYPE_NONE, 1, GDM_TYPE_USER); +- signals [USER_REMOVED] = +- g_signal_new ("user-removed", +- G_TYPE_FROM_CLASS (klass), +- G_SIGNAL_RUN_LAST, +- G_STRUCT_OFFSET (GdmUserManagerClass, user_removed), +- NULL, NULL, +- g_cclosure_marshal_VOID__OBJECT, +- G_TYPE_NONE, 1, GDM_TYPE_USER); +- signals [USER_IS_LOGGED_IN_CHANGED] = +- g_signal_new ("user-is-logged-in-changed", +- G_TYPE_FROM_CLASS (klass), +- G_SIGNAL_RUN_LAST, +- G_STRUCT_OFFSET (GdmUserManagerClass, user_is_logged_in_changed), +- NULL, NULL, +- g_cclosure_marshal_VOID__OBJECT, +- G_TYPE_NONE, 1, GDM_TYPE_USER); +- signals [USER_CHANGED] = +- g_signal_new ("user-changed", +- G_TYPE_FROM_CLASS (klass), +- G_SIGNAL_RUN_LAST, +- G_STRUCT_OFFSET (GdmUserManagerClass, user_changed), +- NULL, NULL, +- g_cclosure_marshal_VOID__OBJECT, +- G_TYPE_NONE, 1, GDM_TYPE_USER); +- +- g_type_class_add_private (klass, sizeof (GdmUserManagerPrivate)); +-} +- +-/** +- * gdm_user_manager_queue_load: +- * @manager: a #GdmUserManager +- * +- * Queue loading users into user manager. This must be called, and the +- * #GdmUserManager:is-loaded property must be %TRUE before calling +- * gdm_user_manager_list_users() +- */ +-void +-gdm_user_manager_queue_load (GdmUserManager *manager) +-{ +- g_return_if_fail (GDM_IS_USER_MANAGER (manager)); +- +- if (! manager->priv->is_loaded) { +- queue_load_seat_and_users (manager); +- } +-} +- +-static void +-gdm_user_manager_init (GdmUserManager *manager) +-{ +- GError *error; +- +- manager->priv = GDM_USER_MANAGER_GET_PRIVATE (manager); +- +- /* sessions */ +- manager->priv->sessions = g_hash_table_new_full (g_str_hash, +- g_str_equal, +- g_free, +- g_free); +- +- /* users */ +- manager->priv->users_by_name = g_hash_table_new_full (g_str_hash, +- g_str_equal, +- g_free, +- g_object_unref); +- +- manager->priv->users_by_object_path = g_hash_table_new_full (g_str_hash, +- g_str_equal, +- NULL, +- g_object_unref); +- +- g_assert (manager->priv->seat.proxy == NULL); +- +- error = NULL; +- manager->priv->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); +- if (manager->priv->connection == NULL) { +- if (error != NULL) { +- g_warning ("Failed to connect to the D-Bus daemon: %s", error->message); +- g_error_free (error); +- } else { +- g_warning ("Failed to connect to the D-Bus daemon"); +- } +- return; +- } +- +- get_accounts_proxy (manager); +- +- manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_UNLOADED; +-} +- +-static void +-gdm_user_manager_finalize (GObject *object) +-{ +- GdmUserManager *manager; +- GSList *node; +- +- g_return_if_fail (object != NULL); +- g_return_if_fail (GDM_IS_USER_MANAGER (object)); +- +- manager = GDM_USER_MANAGER (object); +- +- g_return_if_fail (manager->priv != NULL); +- +- if (manager->priv->ck_history_pid > 0) { +- g_debug ("Killing ck-history process"); +- signal_pid (manager->priv->ck_history_pid, SIGTERM); +- } +- +- g_slist_foreach (manager->priv->new_sessions, +- (GFunc) unload_new_session, NULL); +- g_slist_free (manager->priv->new_sessions); +- +- g_slist_foreach (manager->priv->fetch_user_requests, +- (GFunc) free_fetch_user_request, NULL); +- g_slist_free (manager->priv->fetch_user_requests); +- +- node = manager->priv->new_users; +- while (node != NULL) { +- GdmUser *user; +- GSList *next_node; +- +- user = GDM_USER (node->data); +- next_node = node->next; +- +- g_signal_handlers_disconnect_by_func (user, on_new_user_loaded, manager); +- g_object_unref (user); +- manager->priv->new_users = g_slist_delete_link (manager->priv->new_users, node); +- node = next_node; +- } +- +- unload_seat (manager); +- +- if (manager->priv->exclude_usernames != NULL) { +- g_slist_foreach (manager->priv->exclude_usernames, (GFunc) g_free, NULL); +- g_slist_free (manager->priv->exclude_usernames); +- } +- +- if (manager->priv->include_usernames != NULL) { +- g_slist_foreach (manager->priv->include_usernames, (GFunc) g_free, NULL); +- g_slist_free (manager->priv->include_usernames); +- } +- +- if (manager->priv->seat.proxy != NULL) { +- g_object_unref (manager->priv->seat.proxy); +- } +- +- if (manager->priv->accounts_proxy != NULL) { +- g_object_unref (manager->priv->accounts_proxy); +- } +- +- if (manager->priv->ck_history_id != 0) { +- g_source_remove (manager->priv->ck_history_id); +- manager->priv->ck_history_id = 0; +- } +- +- if (manager->priv->ck_history_watchdog_id != 0) { +- g_source_remove (manager->priv->ck_history_watchdog_id); +- manager->priv->ck_history_watchdog_id = 0; +- } +- +- if (manager->priv->load_id > 0) { +- g_source_remove (manager->priv->load_id); +- manager->priv->load_id = 0; +- } +- +- if (manager->priv->reload_passwd_id > 0) { +- g_source_remove (manager->priv->reload_passwd_id); +- manager->priv->reload_passwd_id = 0; +- } +- +- g_hash_table_destroy (manager->priv->sessions); +- +- if (manager->priv->passwd_monitor != NULL) { +- g_file_monitor_cancel (manager->priv->passwd_monitor); +- } +- +- g_hash_table_destroy (manager->priv->users_by_name); +- g_hash_table_destroy (manager->priv->users_by_object_path); +- +- if (manager->priv->shells_monitor != NULL) { +- g_file_monitor_cancel (manager->priv->shells_monitor); +- } +- +- if (manager->priv->shells != NULL) { +- g_hash_table_destroy (manager->priv->shells); +- } +- +- G_OBJECT_CLASS (gdm_user_manager_parent_class)->finalize (object); +-} +- +-/** +- * gdm_user_manager_ref_default: +- * +- * Queue loading users into user manager. This must be called, and the +- * #GdmUserManager:is-loaded property must be %TRUE before calling +- * gdm_user_manager_list_users() +- * +- * Returns: (transfer full): user manager object +- */ +-GdmUserManager * +-gdm_user_manager_ref_default (void) +-{ +- if (user_manager_object != NULL) { +- g_object_ref (user_manager_object); +- } else { +- user_manager_object = g_object_new (GDM_TYPE_USER_MANAGER, NULL); +- g_object_add_weak_pointer (user_manager_object, +- (gpointer *) &user_manager_object); +- } +- +- return GDM_USER_MANAGER (user_manager_object); +-} +diff --git a/gui/simple-greeter/gdm-user-manager.h b/gui/simple-greeter/gdm-user-manager.h +deleted file mode 100644 +index 8dd9ede..0000000 +--- a/gui/simple-greeter/gdm-user-manager.h ++++ /dev/null +@@ -1,91 +0,0 @@ +-/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- +- * +- * Copyright (C) 2007 William Jon McCann +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License as published by +- * the Free Software Foundation; either version 2 of the License, or +- * (at your option) any later version. +- * +- * This program is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +- * GNU General Public License for more details. +- * +- * You should have received a copy of the GNU General Public License +- * along with this program; if not, write to the Free Software +- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +- * +- */ +- +-#ifndef __GDM_USER_MANAGER_H__ +-#define __GDM_USER_MANAGER_H__ +- +-#include +- +-#include "gdm-user.h" +- +-G_BEGIN_DECLS +- +-#define GDM_TYPE_USER_MANAGER (gdm_user_manager_get_type ()) +-#define GDM_USER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GDM_TYPE_USER_MANAGER, GdmUserManager)) +-#define GDM_USER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GDM_TYPE_USER_MANAGER, GdmUserManagerClass)) +-#define GDM_IS_USER_MANAGER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GDM_TYPE_USER_MANAGER)) +-#define GDM_IS_USER_MANAGER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GDM_TYPE_USER_MANAGER)) +-#define GDM_USER_MANAGER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GDM_TYPE_USER_MANAGER, GdmUserManagerClass)) +- +-typedef struct GdmUserManagerPrivate GdmUserManagerPrivate; +-typedef struct GdmUserManager GdmUserManager; +-typedef struct GdmUserManagerClass GdmUserManagerClass; +-typedef enum GdmUserManagerError GdmUserManagerError; +- +-struct GdmUserManager +-{ +- GObject parent; +- GdmUserManagerPrivate *priv; +-}; +- +-struct GdmUserManagerClass +-{ +- GObjectClass parent_class; +- +- void (* user_added) (GdmUserManager *user_manager, +- GdmUser *user); +- void (* user_removed) (GdmUserManager *user_manager, +- GdmUser *user); +- void (* user_is_logged_in_changed) (GdmUserManager *user_manager, +- GdmUser *user); +- void (* user_changed) (GdmUserManager *user_manager, +- GdmUser *user); +-}; +- +-enum GdmUserManagerError +-{ +- GDM_USER_MANAGER_ERROR_GENERAL, +- GDM_USER_MANAGER_ERROR_KEY_NOT_FOUND +-}; +- +-#define GDM_USER_MANAGER_ERROR gdm_user_manager_error_quark () +- +-GQuark gdm_user_manager_error_quark (void); +-GType gdm_user_manager_get_type (void); +- +-GdmUserManager * gdm_user_manager_ref_default (void); +- +-void gdm_user_manager_queue_load (GdmUserManager *manager); +-GSList * gdm_user_manager_list_users (GdmUserManager *manager); +-GdmUser * gdm_user_manager_get_user (GdmUserManager *manager, +- const char *username); +-GdmUser * gdm_user_manager_get_user_by_uid (GdmUserManager *manager, +- gulong uid); +- +-gboolean gdm_user_manager_activate_user_session (GdmUserManager *manager, +- GdmUser *user); +- +-gboolean gdm_user_manager_can_switch (GdmUserManager *manager); +- +-gboolean gdm_user_manager_goto_login_session (GdmUserManager *manager); +- +-G_END_DECLS +- +-#endif /* __GDM_USER_MANAGER_H */ +diff --git a/gui/simple-greeter/test-user-manager.c b/gui/simple-greeter/test-user-manager.c +index d0f6427..03b7a21 100644 +--- a/gui/simple-greeter/test-user-manager.c ++++ b/gui/simple-greeter/test-user-manager.c +@@ -30,10 +30,12 @@ + #include + #include + +-#include "gdm-user-manager.h" ++#include ++#include ++ + #include "gdm-settings-client.h" + +-static GdmUserManager *manager = NULL; ++static ActUserManager *manager = NULL; + static GMainLoop *main_loop = NULL; + + static gboolean do_monitor = FALSE; +@@ -45,7 +47,7 @@ static GOptionEntry entries [] = { + }; + + static void +-on_is_loaded_changed (GdmUserManager *manager, ++on_is_loaded_changed (ActUserManager *manager, + GParamSpec *pspec, + gpointer data) + { +@@ -53,9 +55,9 @@ on_is_loaded_changed (GdmUserManager *manager, + + g_debug ("Users loaded"); + +- users = gdm_user_manager_list_users (manager); ++ users = act_user_manager_list_users (manager); + while (users != NULL) { +- g_print ("User: %s\n", gdm_user_get_user_name (users->data)); ++ g_print ("User: %s\n", act_user_get_user_name (users->data)); + users = g_slist_delete_link (users, users); + } + +@@ -65,19 +67,19 @@ on_is_loaded_changed (GdmUserManager *manager, + } + + static void +-on_user_added (GdmUserManager *manager, +- GdmUser *user, ++on_user_added (ActUserManager *manager, ++ ActUser *user, + gpointer data) + { +- g_debug ("User added: %s", gdm_user_get_user_name (user)); ++ g_debug ("User added: %s", act_user_get_user_name (user)); + } + + static void +-on_user_removed (GdmUserManager *manager, +- GdmUser *user, ++on_user_removed (ActUserManager *manager, ++ ActUser *user, + gpointer data) + { +- g_debug ("User removed: %s", gdm_user_get_user_name (user)); ++ g_debug ("User removed: %s", act_user_get_user_name (user)); + } + + int +@@ -123,7 +125,7 @@ main (int argc, char *argv[]) + exit (1); + } + +- manager = gdm_user_manager_ref_default (); ++ manager = act_user_manager_get_default (); + g_object_set (manager, "include-all", TRUE, NULL); + g_signal_connect (manager, + "notify::is-loaded", +@@ -137,7 +139,6 @@ main (int argc, char *argv[]) + "user-removed", + G_CALLBACK (on_user_removed), + NULL); +- gdm_user_manager_queue_load (manager); + + main_loop = g_main_loop_new (NULL, FALSE); + +-- +1.7.4.1 + +From f100b21d67382dbdfdc5305f8cbb7f6bc9233f98 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 18 Feb 2011 18:34:31 -0500 +Subject: [PATCH] greeter: filter out root and gdm users from list + +While the accounts service filters out most of the names +we care about, it doesn't filter out the above two, so make +sure they get filtered. +--- + gui/simple-greeter/gdm-user-chooser-widget.c | 8 ++++++++ + 1 files changed, 8 insertions(+), 0 deletions(-) + +diff --git a/gui/simple-greeter/gdm-user-chooser-widget.c b/gui/simple-greeter/gdm-user-chooser-widget.c +index a385218..dd06bc4 100644 +--- a/gui/simple-greeter/gdm-user-chooser-widget.c ++++ b/gui/simple-greeter/gdm-user-chooser-widget.c +@@ -743,6 +743,14 @@ add_user (GdmUserChooserWidget *widget, + return; + } + ++ if (strcmp (act_user_get_user_name (user), GDM_USERNAME) == 0) { ++ return; ++ } ++ ++ if (act_user_get_uid (user) == 0) { ++ return; ++ } ++ + if (widget->priv->stock_person_pixbuf != NULL) { + pixbuf = g_object_ref (widget->priv->stock_person_pixbuf); + } else { +-- +1.7.4.1 +