=== modified file 'configure.ac' --- configure.ac 2011-10-18 21:50:35 +0000 +++ configure.ac 2012-08-23 18:12:57 +0000 @@ -122,6 +122,7 @@ AC_CHECK_HEADERS([shadow.h utmpx.h]) AC_CHECK_FUNCS([fgetpwent]) +AC_CHECK_FUNCS([fgetgrent]) dnl --------------------------------------------------------------------------- dnl - DocBook Documentation === modified file 'src/daemon.c' --- src/daemon.c 2011-11-25 08:28:18 +0000 +++ src/daemon.c 2012-08-27 10:29:37 +0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,7 @@ #define PATH_PASSWD "/etc/passwd" #define PATH_SHADOW "/etc/shadow" +#define PATH_GROUP "/etc/group" #define PATH_LOGIN_DEFS "/etc/login.defs" #define PATH_GDM_CUSTOM "/etc/gdm/custom.conf" @@ -102,11 +104,13 @@ DBusGProxy *bus_proxy; GHashTable *users; + GList *admin_users; GHashTable *exclusions; uid_t minimal_uid; User *autologin; + GFileMonitor *group_monitor; GFileMonitor *passwd_monitor; GFileMonitor *shadow_monitor; GFileMonitor *gdm_monitor; @@ -237,6 +241,21 @@ return FALSE; } + +gint +daemon_local_user_type (Daemon *daemon, const gchar *username, uid_t uid) +{ + + if (uid == 0) { + g_debug ("user is root so account type is administrator"); + return ACCOUNT_TYPE_ADMINISTRATOR; + } + + if( g_list_find (daemon->priv->admin_users, username)) + return ACCOUNT_TYPE_ADMINISTRATOR; + + return ACCOUNT_TYPE_STANDARD; +} static void reload_wtmp_history (Daemon *daemon) { @@ -329,6 +348,55 @@ } static void +reload_group (Daemon *daemon) +{ +#ifdef HAVE_FGETGRENT + int i; + FILE *fp; + gid_t sudo; + gid_t admin; + struct group *grpent; + + g_list_free_full (daemon->priv->admin_users, g_free); + + grpent = getgrnam ("sudo"); + if (grpent == NULL) { + g_debug ("sudo group not found"); + return; + } + sudo = grpent->gr_gid; + + /* Ubuntu prior to 12.04 used "admin" */ + grpent = getgrnam ("admin"); + if (grpent == NULL) { + g_debug ("admin group not found"); + admin = -1; + } else { + admin = grpent->gr_gid; + } + + fp = fopen (PATH_GROUP, "r"); + if (fp == NULL) { + g_warning ("Unable to open %s: %s", PATH_GROUP, g_strerror (errno)); + goto out; + } + + while ((grpent = fgetgrent(fp)) != NULL ) { + if ( grpent->gr_gid == sudo || grpent->gr_gid == admin) { + for(i = 0; grpent->gr_mem[i] != NULL; i++) { + if (! g_list_find (daemon->priv->admin_users, grpent->gr_mem[i])) { + daemon->priv->admin_users = g_list_prepend (daemon->priv->admin_users, g_strdup(grpent->gr_mem[i])); + } + } + } + } + + out: + fclose (fp); +#endif +} + +static void reload_passwd (Daemon *daemon) { struct passwd *pwent; @@ -448,9 +516,15 @@ static void reload_users (Daemon *daemon) { + gint64 time = g_get_monotonic_time (); + + reload_group (daemon); reload_passwd (daemon); reload_wtmp_history (daemon); reload_data (daemon); + + time = g_get_monotonic_time () - time; + g_warning ("done %ld", time); } static gboolean @@ -519,10 +593,10 @@ return; } - /* we wait half a second or so in case /etc/passwd and - * /etc/shadow are changed at the same time, or repeatedly. + /* we wait a second or so in case /etc/passwd , /etc/shadow and + * /etc/group are changed at the same time, or repeatedly. */ - daemon->priv->reload_id = g_timeout_add (500, (GSourceFunc)reload_users_timeout, daemon); + daemon->priv->reload_id = g_timeout_add (1000, (GSourceFunc)reload_users_timeout, daemon); } static void @@ -546,6 +620,21 @@ } static void +on_group_monitor_changed (GFileMonitor *monitor, + GFile *file, + GFile *other_file, + GFileMonitorEvent event_type, + Daemon *daemon) +{ + if (event_type != G_FILE_MONITOR_EVENT_CHANGED && + event_type != G_FILE_MONITOR_EVENT_CREATED) { + return; + } + + queue_reload_users_soon (daemon); +} + +static void on_passwd_monitor_changed (GFileMonitor *monitor, GFile *file, GFile *other_file, @@ -649,10 +738,18 @@ GUINT_TO_POINTER (TRUE)); } + daemon->priv->admin_users = NULL; daemon->priv->users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_object_unref); + + file = g_file_new_for_path (PATH_GROUP); + daemon->priv->group_monitor = g_file_monitor_file (file, + G_FILE_MONITOR_NONE, + NULL, + &error); + g_object_unref (file); file = g_file_new_for_path (PATH_PASSWD); daemon->priv->passwd_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, @@ -672,6 +769,15 @@ &error); g_object_unref (file); + if (daemon->priv->group_monitor != NULL) { + g_signal_connect (daemon->priv->group_monitor, + "changed", + G_CALLBACK (on_group_monitor_changed), + daemon); + } else { + g_warning ("Unable to monitor %s: %s", PATH_GROUP, error->message); + g_error_free (error); + } if (daemon->priv->passwd_monitor != NULL) { g_signal_connect (daemon->priv->passwd_monitor, "changed", @@ -719,6 +825,7 @@ if (daemon->priv->bus_connection != NULL) dbus_g_connection_unref (daemon->priv->bus_connection); + g_list_free_full (daemon->priv->admin_users, g_free); g_hash_table_destroy (daemon->priv->users); G_OBJECT_CLASS (daemon_parent_class)->finalize (object); @@ -1049,7 +1156,7 @@ } if (cd->account_type == ACCOUNT_TYPE_ADMINISTRATOR) { - add_user_to_group (context, cd->user_name, "sudo"); + add_user_to_group (context, cd->user_name, "sudo"); add_user_to_group (context, cd->user_name, "adm"); add_user_to_group (context, cd->user_name, "lpadmin"); add_user_to_group (context, cd->user_name, "sambashare"); === modified file 'src/daemon.h' --- src/daemon.h 2011-04-26 08:20:11 +0000 +++ src/daemon.h 2012-08-26 06:25:35 +0000 @@ -78,6 +78,9 @@ gboolean daemon_local_user_is_excluded (Daemon *daemon, const gchar *name, uid_t uid); +gint daemon_local_user_type (Daemon *daemon, + const gchar *username, + uid_t uid); typedef void (*AuthorizedCallback) (Daemon *daemon, User *user, === modified file 'src/user.c' --- src/user.c 2012-02-16 14:43:00 +0000 +++ src/user.c 2012-08-26 06:23:40 +0000 @@ -608,7 +608,11 @@ /* GID */ user->gid = pwent->pw_gid; +#ifdef HAVE_FGETGRENT + user->account_type = daemon_local_user_type (user->daemon, user->user_name, user->uid); +#else user->account_type = account_type_from_pwent (pwent); +#endif /* Username */ if (g_strcmp0 (user->user_name, pwent->pw_name) != 0) {