Description: Ignore users with UID below system configured minimum.
Bug: https://bugzilla.gnome.org/show_bug.cgi?id=623225
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gdm/+bug/427462
Bug-Ubuntu: https://bugs.launchpad.net/ubuntu/+source/gdm/+bug/459199
Author: Kees Cook <kees@ubuntu.com>

Index: gdm-2.30.4/daemon/gdm-user-manager.c
===================================================================
--- gdm-2.30.4.orig/daemon/gdm-user-manager.c	2010-06-30 10:06:23.127523597 -0700
+++ gdm-2.30.4/daemon/gdm-user-manager.c	2010-06-30 10:06:48.367818683 -0700
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <ctype.h>
 
 #ifdef HAVE_PATHS_H
 #include <paths.h>
@@ -72,7 +73,7 @@
 #ifdef __sun
 #define DEFAULT_MINIMAL_UID     100
 #else
-#define DEFAULT_MINIMAL_UID     500
+#define DEFAULT_MINIMAL_UID     1000
 #endif
 
 #ifndef _PATH_SHELLS
@@ -103,6 +104,7 @@
 
         guint                  reload_id;
         guint                  ck_history_id;
+        guint                  minimal_uid;
 
         guint8                 loaded_passwd : 1;
         guint8                 users_dirty : 1;
@@ -598,6 +600,10 @@
                 return;
         }
 
+        if (pwent->pw_uid < manager->priv->minimal_uid) {
+                return;
+        }
+
         /* check exclusions up front */
         if (user_in_exclude_list (manager, pwent->pw_name)) {
                 g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name);
@@ -929,7 +935,7 @@
                 g_warning ("Unable to lookup user name %s: %s", username, g_strerror (errno));
                 return;
         }
-        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+        if (pwent->pw_uid < manager->priv->minimal_uid) {
                 g_debug ("GdmUserManager: excluding user '%s'", username);
                 return;
         }
@@ -1116,6 +1122,7 @@
         }
 }
 
+
 static void
 reload_passwd (GdmUserManager *manager)
 {
@@ -1161,7 +1168,7 @@
                         user = NULL;
 
                         /* Skip users below MinimalUID... */
-                        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+                        if (pwent->pw_uid < manager->priv->minimal_uid) {
                                 continue;
                         }
 
@@ -1433,6 +1440,39 @@
         g_strfreev (temp_array);
 }
 
+
+static guint
+system_minimal_uid (void)
+{
+        guint  uid = DEFAULT_MINIMAL_UID;
+#ifndef __sun
+        char *defspath = "/etc/login.defs";
+        FILE *fp;
+        char line[128];
+
+        errno = 0;
+        fp = fopen (defspath, "r");
+        if (fp == NULL) {
+                g_warning ("Unable to open %s: %s", defspath, g_strerror (errno));
+                goto out;
+        }
+        while (fgets (line, sizeof(line), fp)) {
+            if (strncmp (line, "UID_MIN", 7) == 0) {
+                char *ptr = line + 7;
+                int  value;
+                while (*ptr && isblank (*ptr)) { ptr++; }
+                value = atoi (ptr);
+                if (value) uid = value;
+                break;
+            }
+        }
+        fclose (fp);
+#endif
+out:
+        return uid;
+}
+
+
 static void
 gdm_user_manager_init (GdmUserManager *manager)
 {
@@ -1458,6 +1498,8 @@
         res = gdm_settings_direct_get_boolean (GDM_KEY_INCLUDE_ALL,
                                                &manager->priv->include_all);
 
+        manager->priv->minimal_uid = system_minimal_uid ();
+
         /* sessions */
         manager->priv->sessions = g_hash_table_new_full (g_str_hash,
                                                          g_str_equal,
Index: gdm-2.30.4/gui/gdmsetup/gdm-user-manager.c
===================================================================
--- gdm-2.30.4.orig/gui/gdmsetup/gdm-user-manager.c	2010-06-30 10:06:23.027522430 -0700
+++ gdm-2.30.4/gui/gdmsetup/gdm-user-manager.c	2010-06-30 10:06:48.367818683 -0700
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <ctype.h>
 
 #ifdef HAVE_PATHS_H
 #include <paths.h>
@@ -66,7 +67,7 @@
 #ifdef __sun
 #define DEFAULT_MINIMAL_UID     100
 #else
-#define DEFAULT_MINIMAL_UID     500
+#define DEFAULT_MINIMAL_UID     1000
 #endif
 
 #ifndef _PATH_SHELLS
@@ -112,6 +113,7 @@
 
         guint                  reload_id;
         guint                  ck_history_id;
+        guint                  minimal_uid;
 
         guint8                 users_dirty : 1;
 };
@@ -835,6 +837,10 @@
                 return;
         }
 
+        if (pwent->pw_uid < manager->priv->minimal_uid) {
+                return;
+        }
+
         /* check exclusions up front */
         if (g_hash_table_lookup (manager->priv->exclusions, pwent->pw_name)) {
                 g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name);
@@ -1154,7 +1160,7 @@
                 g_warning ("Unable to lookup user name %s: %s", username, g_strerror (errno));
                 return;
         }
-        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+        if (pwent->pw_uid < manager->priv->minimal_uid) {
                 g_debug ("GdmUserManager: excluding user '%s'", username);
                 return;
         }
@@ -1317,7 +1323,7 @@
                 user = NULL;
 
                 /* Skip users below MinimalUID... */
-                if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+                if (pwent->pw_uid < manager->priv->minimal_uid) {
                         continue;
                 }
 
@@ -1525,6 +1531,39 @@
         g_type_class_add_private (klass, sizeof (GdmUserManagerPrivate));
 }
 
+
+static guint
+system_minimal_uid (void)
+{
+        guint  uid = DEFAULT_MINIMAL_UID;
+#ifndef __sun
+        char *defspath = "/etc/login.defs";
+        FILE *fp;
+        char line[128];
+
+        errno = 0;
+        fp = fopen (defspath, "r");
+        if (fp == NULL) {
+                g_warning ("Unable to open %s: %s", defspath, g_strerror (errno));
+                goto out;
+        }
+        while (fgets (line, sizeof(line), fp)) {
+            if (strncmp (line, "UID_MIN", 7) == 0) {
+                char *ptr = line + 7;
+                int  value;
+                while (*ptr && isblank (*ptr)) { ptr++; }
+                value = atoi (ptr);
+                if (value) uid = value;
+                break;
+            }
+        }
+        fclose (fp);
+#endif
+out:
+        return uid;
+}
+
+
 static void
 gdm_user_manager_init (GdmUserManager *manager)
 {
@@ -1535,6 +1574,8 @@
 
         manager->priv = GDM_USER_MANAGER_GET_PRIVATE (manager);
 
+        manager->priv->minimal_uid = system_minimal_uid ();
+
         /* sessions */
         manager->priv->sessions = g_hash_table_new_full (g_str_hash,
                                                          g_str_equal,
Index: gdm-2.30.4/gui/simple-greeter/gdm-user-manager.c
===================================================================
--- gdm-2.30.4.orig/gui/simple-greeter/gdm-user-manager.c	2010-06-30 10:06:22.917521143 -0700
+++ gdm-2.30.4/gui/simple-greeter/gdm-user-manager.c	2010-06-30 10:14:32.703275441 -0700
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <ctype.h>
 
 #ifdef HAVE_PATHS_H
 #include <paths.h>
@@ -63,7 +64,7 @@
 #ifdef __sun
 #define DEFAULT_MINIMAL_UID     100
 #else
-#define DEFAULT_MINIMAL_UID     500
+#define DEFAULT_MINIMAL_UID     1000
 #endif
 
 #ifndef _PATH_SHELLS
@@ -153,6 +154,7 @@
 
         gboolean               is_loaded;
         gboolean               has_multiple_users;
+        guint                  minimal_uid;
 };
 
 enum {
@@ -1016,6 +1018,10 @@
                 goto failed;
         }
 
+        if (pwent->pw_uid < manager->priv->minimal_uid) {
+                return;
+        }
+
         /* check exclusions up front */
         if (username_in_exclude_list (manager, pwent->pw_name)) {
                 g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name);
@@ -1446,7 +1452,7 @@
                 g_warning ("Unable to lookup user name %s: %s", username, g_strerror (errno));
                 return;
         }
-        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+        if (pwent->pw_uid < manager->priv->minimal_uid) {
                 g_debug ("GdmUserManager: excluding user '%s'", username);
                 return;
         }
@@ -1673,6 +1679,7 @@
 
 static void
 reload_passwd_file (GHashTable *valid_shells,
+                    GdmUserManager *manager,
                     GSList     *exclude_users,
                     GSList     *include_users,
                     gboolean    include_all,
@@ -1751,7 +1758,7 @@
                      pwent = fgetpwent (fp)) {
 
                         /* Skip users below MinimalUID... */
-                        if (pwent->pw_uid < DEFAULT_MINIMAL_UID) {
+                        if (pwent->pw_uid < manager->priv->minimal_uid) {
                                 continue;
                         }
 
@@ -1907,6 +1914,7 @@
         g_debug ("GdmUserManager: reloading passwd file worker");
 
         reload_passwd_file (data->shells,
+                            data->manager,
                             data->exclude_users,
                             data->include_users,
                             data->include_all,
@@ -2020,6 +2028,38 @@
         maybe_set_is_loaded (manager);
 }
 
+static guint
+system_minimal_uid (void)
+{
+        guint  uid = DEFAULT_MINIMAL_UID;
+#ifndef __sun
+        char *defspath = "/etc/login.defs";
+        FILE *fp;
+        char line[128];
+
+        errno = 0;
+        fp = fopen (defspath, "r");
+        if (fp == NULL) {
+                g_warning ("Unable to open %s: %s", defspath, g_strerror (errno));
+                goto out;
+        }
+        while (fgets (line, sizeof(line), fp)) {
+            if (strncmp (line, "UID_MIN", 7) == 0) {
+                char *ptr = line + 7;
+                int  value;
+                while (*ptr && isblank (*ptr)) { ptr++; }
+                value = atoi (ptr);
+                if (value) uid = value;
+                break;
+            }
+        }
+        fclose (fp);
+#endif
+out:
+        return uid;
+}
+
+
 static void
 load_sessions (GdmUserManager *manager)
 {
@@ -2412,6 +2452,7 @@
         GError        *error;
 
         manager->priv = GDM_USER_MANAGER_GET_PRIVATE (manager);
+        manager->priv->minimal_uid = system_minimal_uid ();
 
         /* sessions */
         manager->priv->sessions = g_hash_table_new_full (g_str_hash,
