Blob Blame Raw
From 450731558cbd5c77aa6932d35f27abf898553db6 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Tue, 6 Sep 2016 13:54:48 -0400
Subject: [PATCH] user-classify: exclude nologin users

Sometimes admins set a user's shell to nologin to hide it from
the user list.  This commit fixes accountsservice so that behavior
works again.
---
 src/user-classify.c | 77 +++++++++++++++++++++++++++++------------------------
 1 file changed, 42 insertions(+), 35 deletions(-)

diff --git a/src/user-classify.c b/src/user-classify.c
index 69e6809..b79a35f 100644
--- a/src/user-classify.c
+++ b/src/user-classify.c
@@ -1,169 +1,176 @@
 /*
  * 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 <desrt@desrt.ca>
  *          Matthias Clasen <mclasen@redhat.com>
  */
 
 #include "config.h"
 
 #include "user-classify.h"
 
 #include <string.h>
+#include <unistd.h>
 
 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"
 };
 
 static gboolean
 user_classify_is_blacklisted (const char *username)
 {
         static GHashTable *exclusions;
 
         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;
 }
 #endif /* ENABLE_USER_HEURISTICS */
 
+static gboolean
+is_invalid_shell (const char *shell)
+{
+        char *basename, *nologin_basename, *false_basename;
+        int ret = FALSE;
+
+#ifdef HAVE_GETUSERSHELL
+        char *valid_shell;
+
+        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);
+
+        return ret;
+}
+
 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;
 
+        if (shell != NULL && is_invalid_shell (shell))
+                return FALSE;
+
 #ifdef ENABLE_USER_HEURISTICS
         /* 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))
+                if (!user_classify_is_excluded_by_heuristics (username, password_hash))
                         return TRUE;
         }
 #endif
 
         return uid >= MINIMUM_UID;
 }
-- 
2.7.4