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