diff --git a/SOURCES/fix-leak.patch b/SOURCES/fix-leak.patch new file mode 100644 index 0000000..ca12772 --- /dev/null +++ b/SOURCES/fix-leak.patch @@ -0,0 +1,86 @@ +From cfee906f39afa58d883e4fbed1888274c79c6e30 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Wed, 29 Jan 2014 10:29:04 -0500 +Subject: [PATCH] user: fix memory leak in save_extra_data function + +The save_extra_data function serializes a key file +assocated with the user to disk. + +It fails to free the in memory buffer, however. + +This commit fixes that. + +see downstream bug https://bugzilla.redhat.com/show_bug.cgi?id=1003033 +--- + src/user.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/user.c b/src/user.c +index 163d136..de30090 100644 +--- a/src/user.c ++++ b/src/user.c +@@ -407,60 +407,61 @@ user_save_to_keyfile (User *user, + + if (user->location) + g_key_file_set_string (keyfile, "User", "Location", user->location); + + if (user->password_hint) + g_key_file_set_string (keyfile, "User", "PasswordHint", user->password_hint); + + if (user->icon_file) + g_key_file_set_string (keyfile, "User", "Icon", user->icon_file); + + g_key_file_set_boolean (keyfile, "User", "SystemAccount", user->system_account); + } + + static void + save_extra_data (User *user) + { + gchar *filename; + gchar *data; + GError *error; + + user_save_to_keyfile (user, user->keyfile); + + error = NULL; + data = g_key_file_to_data (user->keyfile, NULL, &error); + if (error == NULL) { + filename = g_build_filename (USERDIR, + user->user_name, + NULL); + g_file_set_contents (filename, data, -1, &error); + g_free (filename); ++ g_free (data); + } + if (error) { + g_warning ("Saving data for user %s failed: %s", + user->user_name, error->message); + g_error_free (error); + } + } + + static void + move_extra_data (const gchar *old_name, + const gchar *new_name) + { + gchar *old_filename; + gchar *new_filename; + + old_filename = g_build_filename (USERDIR, + old_name, NULL); + new_filename = g_build_filename (USERDIR, + new_name, NULL); + + g_rename (old_filename, new_filename); + + g_free (old_filename); + g_free (new_filename); + } + + static gchar * + compute_object_path (User *user) + { + gchar *object_path; +-- +1.8.4.2 + diff --git a/SOURCES/fix-user-classification-logic.patch b/SOURCES/fix-user-classification-logic.patch new file mode 100644 index 0000000..b241b32 --- /dev/null +++ b/SOURCES/fix-user-classification-logic.patch @@ -0,0 +1,377 @@ +From 1ef1e18936f1bfad019f3d6427135629f4bdc2a1 Mon Sep 17 00:00:00 2001 +From: Ray Strode +Date: Fri, 15 Nov 2013 10:11:15 -0500 +Subject: [PATCH] Change up user classification logic again + +relying on login.defs is fragile, and the +user heuristics are fragile. + +This commit requires an explicit uid minimum +get configured, and heuristics now only get +applied to the specific problematic range +they were added to address. + +https://bugs.freedesktop.org/show_bug.cgi?id=71801 +--- + configure.ac | 8 +++- + src/user-classify.c | 129 ++++++++++------------------------------------------ + 2 files changed, 32 insertions(+), 105 deletions(-) + +diff --git a/configure.ac b/configure.ac +index a7f4e20..eb5360e 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -28,65 +28,71 @@ AC_SUBST(LT_AGE) + PKG_CHECK_MODULES(GIO, gio-2.0 gio-unix-2.0) + PKG_CHECK_MODULES(POLKIT, gio-unix-2.0 polkit-gobject-1) + + AM_MAINTAINER_MODE([enable]) + + # client library dependencies + LIBACCOUNTSSERVICE_LIBS="$GIO_LIBS" + AC_SUBST(LIBACCOUNTSSERVICE_LIBS) + LIBACCOUNTSSERVICE_CFLAGS="$GIO_CFLAGS" + AC_SUBST(LIBACCOUNTSSERVICE_CFLAGS) + + GOBJECT_INTROSPECTION_CHECK([0.9.12]) + + dnl --------------------------------------------------------------------------- + dnl - Core configuration + dnl --------------------------------------------------------------------------- + + AC_ARG_ENABLE(admin-group, + [AS_HELP_STRING([--enable-admin-group],[Set group for administrative accounts @<:@default=auto@:>@])], + ,enable_admin_group=auto) + AS_IF([test x$enable_admin_group = xauto], [ + AC_CHECK_FILE(/etc/redhat-release, enable_admin_group=wheel) + AC_CHECK_FILE(/etc/debian_version, enable_admin_group=sudo) + AS_IF([test x$enable_admin_group = xauto], [ + enable_admin_group=wheel + ]) + ]) + AC_DEFINE_UNQUOTED([ADMIN_GROUP], ["$enable_admin_group"], [Define to the group for administrator users]) + + AC_ARG_ENABLE(user-heuristics, +- [AS_HELP_STRING([--enable-user-heuristics],[Enable heuristics for guessing system vs. human users])], ++ [AS_HELP_STRING([--enable-user-heuristics],[Enable heuristics for guessing system vs. human users in the range 500-minimum-uid])], + [if test "$enableval" = yes; then + AC_DEFINE([ENABLE_USER_HEURISTICS], , [System vs. human user heuristics enabled]) + fi]) + ++AC_ARG_WITH(minimum-uid, ++ [AS_HELP_STRING([--with-minimum-uid],[Set minimum uid for human users])], ++ ,with_minimum_uid=1000) ++ ++AC_DEFINE_UNQUOTED([MINIMUM_UID], $with_minimum_uid, [Define to the minumum UID of human users]) ++ + dnl --------------------------------------------------------------------------- + dnl - coverage + dnl --------------------------------------------------------------------------- + + AC_MSG_CHECKING([whether to build with gcov testing]) + AC_ARG_ENABLE([coverage], + AS_HELP_STRING([--enable-coverage], + [Whether to enable gcov code coverage]), + [], [enable_coverage=no]) + AC_MSG_RESULT([$enable_coverage]) + + if test "$enable_coverage" = "yes"; then + if test "$GCC" != "yes"; then + AC_MSG_ERROR(Coverage testing requires GCC) + fi + CFLAGS="$CFLAGS -O0 -g --coverage" + fi + + AM_CONDITIONAL([WITH_COVERAGE], [test "$enable_coverage" = "yes"]) + + dnl --------------------------------------------------------------------------- + dnl - Warnings + dnl --------------------------------------------------------------------------- + + AC_ARG_ENABLE(more-warnings, + AS_HELP_STRING([--enable-more-warnings], + [Maximum compiler warnings]), + set_more_warnings="$enableval",[ + if test -d $srcdir/.git; then + set_more_warnings=yes +diff --git a/src/user-classify.c b/src/user-classify.c +index b68c9ae..69e6809 100644 +--- a/src/user-classify.c ++++ b/src/user-classify.c +@@ -1,248 +1,169 @@ + /* + * Copyright (C) 2009-2010 Red Hat, Inc. + * Copyright (C) 2013 Canonical Limited + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the licence, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Ryan Lortie + * Matthias Clasen + */ + + #include "config.h" + + #include "user-classify.h" + + #include + +-#ifdef ENABLE_USER_HEURISTICS + static const char *default_excludes[] = { + "bin", + "root", + "daemon", + "adm", + "lp", + "sync", + "shutdown", + "halt", + "mail", + "news", + "uucp", + "operator", + "nobody", + "nobody4", + "noaccess", + "postgres", + "pvm", + "rpm", + "nfsnobody", + "pcap", + "mysql", + "ftp", + "games", + "man", + "at", + "gdm", + "gnome-initial-setup" + }; + +-#define PATH_NOLOGIN "/sbin/nologin" +-#define PATH_FALSE "/bin/false" +- + static gboolean +-user_classify_is_excluded_by_heuristics (const gchar *username, +- const gchar *shell, +- const gchar *password_hash) ++user_classify_is_blacklisted (const char *username) + { + static GHashTable *exclusions; +- gboolean ret = FALSE; + + if (exclusions == NULL) { + guint i; + + exclusions = g_hash_table_new (g_str_hash, g_str_equal); + + for (i = 0; i < G_N_ELEMENTS (default_excludes); i++) { + g_hash_table_add (exclusions, (gpointer) default_excludes[i]); + } + } + + if (g_hash_table_contains (exclusions, username)) { + return TRUE; + } + ++ return FALSE; ++} ++ ++#define PATH_NOLOGIN "/sbin/nologin" ++#define PATH_FALSE "/bin/false" ++ ++#ifdef ENABLE_USER_HEURISTICS ++static gboolean ++user_classify_is_excluded_by_heuristics (const gchar *username, ++ const gchar *shell, ++ const gchar *password_hash) ++{ ++ gboolean ret = FALSE; ++ + if (shell != NULL) { + char *basename, *nologin_basename, *false_basename; + + #ifdef HAVE_GETUSERSHELL + char *valid_shell; + + ret = TRUE; + setusershell (); + while ((valid_shell = getusershell ()) != NULL) { + if (g_strcmp0 (shell, valid_shell) != 0) + continue; + ret = FALSE; + } + endusershell (); + #endif + + basename = g_path_get_basename (shell); + nologin_basename = g_path_get_basename (PATH_NOLOGIN); + false_basename = g_path_get_basename (PATH_FALSE); + + if (shell[0] == '\0') { + ret = TRUE; + } else if (g_strcmp0 (basename, nologin_basename) == 0) { + ret = TRUE; + } else if (g_strcmp0 (basename, false_basename) == 0) { + ret = TRUE; + } + + g_free (basename); + g_free (nologin_basename); + g_free (false_basename); + } + + if (password_hash != NULL) { + /* skip over the account-is-locked '!' prefix if present */ + if (password_hash[0] == '!') + password_hash++; + + if (password_hash[0] != '\0') { + /* modern hashes start with "$n$" */ + if (password_hash[0] == '$') { + if (strlen (password_hash) < 4) + ret = TRUE; + + /* DES crypt is base64 encoded [./A-Za-z0-9]* + */ + } else if (!g_ascii_isalnum (password_hash[0]) && + password_hash[0] != '.' && + password_hash[0] != '/') { + ret = TRUE; + } + } + + } + + return ret; + } +- +-#else /* ENABLE_USER_HEURISTICS */ +- +-static gboolean +-user_classify_parse_login_defs_field (const gchar *contents, +- const gchar *key, +- uid_t *result) +-{ +- gsize key_len; +- gint64 value; +- gchar *end; +- +- key_len = strlen (key); +- +- for (;;) { +- /* Our key has to be at the start of the line, followed by whitespace */ +- if (strncmp (contents, key, key_len) == 0 && g_ascii_isspace (contents[key_len])) { +- /* Found it. Move contents past the key itself and break out. */ +- contents += key_len; +- break; +- } +- +- /* Didn't find it. Find the end of the line. */ +- contents = strchr (contents, '\n'); +- +- /* EOF? */ +- if (!contents) { +- /* We didn't find the field... */ +- return FALSE; +- } +- +- /* Start at the beginning of the next line on next iteration. */ +- contents++; +- } +- +- /* 'contents' now points at the whitespace character just after +- * the field name. strtoll can deal with that. +- */ +- value = g_ascii_strtoll (contents, &end, 10); +- +- if (*end && !g_ascii_isspace (*end)) { +- g_warning ("Trailing junk after '%s' field in login.defs", key); +- return FALSE; +- } +- +- if (value <= 0 || value >= G_MAXINT32) { +- g_warning ("Value for '%s' field out of range", key); +- return FALSE; +- } +- +- *result = value; +- +- return TRUE; +-} +- +-static void +-user_classify_read_login_defs (uid_t *min_uid, +- uid_t *max_uid) +-{ +- GError *error = NULL; +- char *contents; +- +- if (!g_file_get_contents ("/etc/login.defs", &contents, NULL, &error)) { +- g_warning ("Could not open /etc/login.defs: %s. Falling back to default human uid range of %d to %d", +- error->message, (int) *min_uid, (int) *max_uid); +- g_error_free (error); +- return; +- } +- +- if (!user_classify_parse_login_defs_field (contents, "UID_MIN", min_uid)) { +- g_warning ("Could not find UID_MIN value in login.defs. Using default of %d", (int) *min_uid); +- } +- +- if (!user_classify_parse_login_defs_field (contents, "UID_MAX", max_uid)) { +- g_warning ("Could not find UID_MIN value in login.defs. Using default of %d", (int) *max_uid); +- } +- +- g_free (contents); +-} +- +-static gboolean +-user_classify_is_in_human_range (uid_t uid) +-{ +- static uid_t min_uid = 1000, max_uid = 60000; +- static gboolean initialised; +- +- if (!initialised) { +- user_classify_read_login_defs (&min_uid, &max_uid); +- initialised = TRUE; +- } +- +- return min_uid <= uid && uid <= max_uid; +-} + #endif /* ENABLE_USER_HEURISTICS */ + + gboolean + user_classify_is_human (uid_t uid, + const gchar *username, + const gchar *shell, + const gchar *password_hash) + { ++ if (user_classify_is_blacklisted (username)) ++ return FALSE; ++ + #ifdef ENABLE_USER_HEURISTICS +- return !user_classify_is_excluded_by_heuristics (username, shell, password_hash); +-#else +- return user_classify_is_in_human_range (uid); ++ /* only do heuristics on the range 500-1000 to catch one off migration problems in Fedora */ ++ if (uid >= 500 && uid < MINIMUM_UID) { ++ if (!user_classify_is_excluded_by_heuristics (username, shell, password_hash)) ++ return TRUE; ++ } + #endif ++ ++ return uid >= MINIMUM_UID; + } +-- +1.8.3.1 + diff --git a/SOURCES/userdel-f.patch b/SOURCES/userdel-f.patch new file mode 100644 index 0000000..003d69e --- /dev/null +++ b/SOURCES/userdel-f.patch @@ -0,0 +1,32 @@ +From 77e2d73723aaef376d97597a61328619b8a204c3 Mon Sep 17 00:00:00 2001 +From: Matthias Clasen +Date: Fri, 10 Jan 2014 12:38:55 -0500 +Subject: [PATCH] Call userdel consistently + +When deleting the users files, we use -f, otherwise we don't. This +leads to inconsistent behaviour. Always pass -f. +--- + src/daemon.c | 7 ++++--- + 1 file changed, 4 insertions(+), 3 deletions(-) + +diff --git a/src/daemon.c b/src/daemon.c +index b2720f4..cb36f01 100644 +--- a/src/daemon.c ++++ b/src/daemon.c +@@ -1289,9 +1289,10 @@ daemon_delete_user_authorized_cb (Daemon *daemon, + argv[5] = NULL; + } + else { +- argv[1] = "--"; +- argv[2] = pwent->pw_name; +- argv[3] = NULL; ++ argv[1] = "-f"; ++ argv[2] = "--"; ++ argv[3] = pwent->pw_name; ++ argv[4] = NULL; + } + + error = NULL; +-- +1.8.4.2 + diff --git a/SPECS/accountsservice.spec b/SPECS/accountsservice.spec index f86b7e4..c9e6be8 100644 --- a/SPECS/accountsservice.spec +++ b/SPECS/accountsservice.spec @@ -2,7 +2,7 @@ Name: accountsservice Version: 0.6.35 -Release: 2%{?dist} +Release: 7%{?dist} Summary: D-Bus interfaces for querying and manipulating user account information Group: System Environment/Daemons @@ -30,6 +30,9 @@ Requires(postun): systemd-units Patch0: rip-out-extension-interface.patch Patch1: 0001-Avoid-deleting-the-root-user.patch +Patch2: fix-user-classification-logic.patch +Patch3: userdel-f.patch +Patch4: fix-leak.patch %package libs Summary: Client-side library to talk to accountsservice @@ -62,10 +65,13 @@ of these interfaces, based on the useradd, usermod and userdel commands. %setup -q %patch0 -p1 -b .rip-out-extension-interface %patch1 -p1 -b .dont-delete-root +%patch2 -p1 -b .fix-user-classification-logic +%patch3 -p1 -b .userdel-f +%patch4 -p1 -b .fix-leak %build autoreconf -f -i -%configure +%configure --enable-user-heuristics make %{?_smp_mflags} @@ -116,6 +122,25 @@ rm $RPM_BUILD_ROOT%{_libdir}/*.a %{_datadir}/gtk-doc/html/libaccountsservice/* %changelog +* Wed Jan 29 2014 Ray Strode 0.6.35-7 +- Fix memory leak + Resolves: #1003033 + +* Tue Jan 28 2014 Daniel Mach - 0.6.35-6 +- Mass rebuild 2014-01-24 + +* Fri Jan 10 2014 Matthias Clasen 0.6.35-5 +- Consistently call userdel -f +Resolves: #1051629 + +* Fri Dec 27 2013 Daniel Mach - 0.6.35-4 +- Mass rebuild 2013-12-27 + +* Tue Nov 19 2013 Ray Strode 0.6.35-3 +- Fix up user classification logic to work better with + remote users. + Resolves: #1029195 + * Fri Nov 1 2013 Matthias Clasen 0.6.35-2 - Refuse to delete the root user - Resolves: #1002973