diff -Naurp accountsservice-0.6.15/configure.ac accountsservice-0.6.15.limit/configure.ac --- accountsservice-0.6.15/configure.ac 2013-01-28 15:18:41.000000000 +0530 +++ accountsservice-0.6.15.limit/configure.ac 2013-01-28 14:17:07.669879112 +0530 @@ -122,6 +122,9 @@ AC_SUBST(WARN_CFLAGS) AC_CHECK_HEADERS([shadow.h utmpx.h]) AC_CHECK_FUNCS([fgetpwent]) +AC_CHECK_FUNCS([fgetgrent]) +AC_CHECK_FUNCS([fgetspent]) + dnl --------------------------------------------------------------------------- dnl - DocBook Documentation diff -Naurp accountsservice-0.6.15/src/daemon.c accountsservice-0.6.15.limit/src/daemon.c --- accountsservice-0.6.15/src/daemon.c 2013-01-28 15:18:41.000000000 +0530 +++ accountsservice-0.6.15.limit/src/daemon.c 2013-01-28 14:18:20.993858357 +0530 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -35,6 +36,9 @@ #ifdef HAVE_UTMPX_H #include #endif +#ifdef HAVE_SHADOW_H +#include +#endif #include #include @@ -51,6 +55,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 +107,14 @@ struct DaemonPrivate { DBusGProxy *bus_proxy; GHashTable *users; + GHashTable *shadow_users; + GList *admin_users; GHashTable *exclusions; uid_t minimal_uid; User *autologin; + GFileMonitor *group_monitor; GFileMonitor *passwd_monitor; GFileMonitor *shadow_monitor; GFileMonitor *gdm_monitor; @@ -310,13 +318,16 @@ reload_wtmp_history (Daemon *daemon) } static void -listify_hash_values_hfunc (gpointer key, +clone_hash_values_hfunc (gpointer key, gpointer value, gpointer user_data) { - GSList **list = user_data; + GHashTable *hash = user_data; + User *user = value; - *list = g_slist_prepend (*list, value); + g_hash_table_insert (hash, + g_strdup (user_local_get_user_name (user)), + g_object_ref (user)); } static gint @@ -328,20 +339,187 @@ compare_user_name (gconstpointer a, gcon return g_strcmp0 (user_local_get_user_name (user), name); } +typedef struct { + gboolean locked; + PasswordMode mode; +} DaemonUserPrivate; + +static PasswordMode +password_type (const gchar *passwd, gboolean *locked) +{ + PasswordMode mode; + if (passwd && (passwd[0] == '!'|| passwd[0] == '*')) { + *locked = TRUE; + } + else { + *locked = FALSE; + } + + if (passwd[0] == 0) { + mode = PASSWORD_MODE_NONE; + } + else { + mode = PASSWORD_MODE_REGULAR; + } + + return mode; +} + +PasswordMode +daemon_local_password_type(Daemon *daemon,const gchar *name, const gchar *passwd, gboolean *locked) +{ +#if 1 +#warning testing code +//#ifdef HAVE_FGETSPENT + GList *data; + DaemonUserPrivate *user; + PasswordMode mode = PASSWORD_MODE_NONE; + *locked = TRUE; + + user = g_hash_table_lookup (daemon->priv->shadow_users, name); + if (user) { + *locked = user->locked; + mode = user->mode; + } +#else + mode = password_type (passwd, locked) +#endif + + return mode; +} + +static void +reload_shadow (Daemon *daemon) +{ +#if 1 +#warning testing code +// #ifdef HAVE_FGETSPENT + FILE *fp; + struct spwd *spent; + + errno = 0; + fp = fopen (PATH_SHADOW, "r"); + if (fp == NULL) { + g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno)); + goto out; + } + + g_hash_table_remove_all (daemon->priv->users); + + while ((spent = fgetspent (fp)) != NULL) { + gboolean locked; + PasswordMode mode; + DaemonUserPrivate *user_data; + + user_data = g_malloc0 (sizeof(DaemonUserPrivate)); + + mode = password_type ( spent->sp_pwdp, &locked); + if (spent->sp_lstchg == 0) { + mode = PASSWORD_MODE_SET_AT_LOGIN; + } + + user_data->mode = mode; + user_data->locked = locked; + + g_hash_table_insert (daemon->priv->shadow_users, + g_strdup (spent->sp_pwdp), user_data); + + } + +out: + fclose (fp); + +#endif +} + +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_group (Daemon *daemon) +{ +#if 1 +#warning testing code +//#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; - GSList *old_users; - GSList *new_users; - GSList *list; + GHashTable *old_users; + GHashTable *new_users; + #ifdef HAVE_FGETPWENT FILE *fp; #endif + GHashTableIter iter; + gpointer key, value; User *user = NULL; - old_users = NULL; - new_users = NULL; + old_users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); + new_users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); #ifdef HAVE_FGETPWENT errno = 0; @@ -353,8 +531,7 @@ reload_passwd (Daemon *daemon) #else setpwent(); #endif - g_hash_table_foreach (daemon->priv->users, listify_hash_values_hfunc, &old_users); - g_slist_foreach (old_users, (GFunc) g_object_ref, NULL); + g_hash_table_foreach (daemon->priv->users, clone_hash_values_hfunc, &old_users); #ifdef HAVE_FGETPWENT while ((pwent = fgetpwent (fp)) != NULL) { @@ -368,7 +545,7 @@ reload_passwd (Daemon *daemon) } /* ignore duplicate entries */ - if (g_slist_find_custom (new_users, pwent->pw_name, compare_user_name)) { + if (g_hash_table_lookup (new_users, pwent->pw_name)) { continue; } @@ -383,30 +560,38 @@ reload_passwd (Daemon *daemon) g_object_freeze_notify (G_OBJECT (user)); user_local_update_from_pwent (user, pwent); - new_users = g_slist_prepend (new_users, user); + g_hash_table_insert (new_users, + g_strdup (user_local_get_user_name (user)), + user); } /* Go through and handle removed users */ - for (list = old_users; list; list = list->next) { - user = list->data; - if (! g_slist_find (new_users, user)) { - g_signal_emit (daemon, signals[USER_REMOVED], 0, user_local_get_object_path (user)); - user_local_unregister (user); - g_hash_table_remove (daemon->priv->users, - user_local_get_user_name (user)); - } - } + g_hash_table_iter_init (&iter, old_users); + while (g_hash_table_iter_next (&iter, &key, &value)) { + user = value; + if (!g_hash_table_lookup ( new_users, value)) { + g_signal_emit (daemon, signals[USER_REMOVED], 0, + user_local_get_object_path (user)); + + user_local_unregister (user); + g_hash_table_remove (daemon->priv->users, + user_local_get_user_name (user)); + } + } + /* Go through and handle added users or update display names */ - for (list = new_users; list; list = list->next) { - user = list->data; - if (!g_slist_find (old_users, user)) { + g_hash_table_iter_init (&iter, new_users); + while (g_hash_table_iter_next (&iter, &key, &value)) { + user = value; + if (!g_hash_table_lookup (old_users, user)) { user_local_register (user); g_hash_table_insert (daemon->priv->users, - g_strdup (user_local_get_user_name (user)), - g_object_ref (user)); + g_strdup (user_local_get_user_name (user)), + g_object_ref (user)); - g_signal_emit (daemon, signals[USER_ADDED], 0, user_local_get_object_path (user)); + g_signal_emit (daemon, signals[USER_ADDED], 0, + user_local_get_object_path (user)); } } @@ -417,12 +602,8 @@ reload_passwd (Daemon *daemon) fclose (fp); #endif - g_slist_foreach (new_users, (GFunc) g_object_thaw_notify, NULL); - g_slist_foreach (new_users, (GFunc) g_object_unref, NULL); - g_slist_free (new_users); - - g_slist_foreach (old_users, (GFunc) g_object_unref, NULL); - g_slist_free (old_users); + g_hash_table_destroy (new_users); + g_hash_table_destroy (old_users); } static void @@ -448,9 +629,16 @@ reload_data (Daemon *daemon) static void reload_users (Daemon *daemon) { + gint64 time = g_get_monotonic_time (); + + reload_group (daemon); + reload_shadow (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,20 +707,23 @@ queue_reload_users_soon (Daemon *daemon) 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_seconds (1, (GSourceFunc)reload_users_timeout, daemon); } static void queue_reload_users (Daemon *daemon) { - if (daemon->priv->reload_id > 0) { - return; - } - - daemon->priv->reload_id = g_idle_add ((GSourceFunc)reload_users_timeout, daemon); +// if (daemon->priv->reload_id > 0) { + // return; + // } + +#warning testing code + reload_users(daemon); +// The first run will take a loong time +// daemon->priv->reload_id = g_timeout_add_seconds (120,(GSourceFunc)reload_users_timeout, daemon); } static void @@ -546,6 +737,21 @@ queue_reload_autologin (Daemon *daemon) } 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 +855,22 @@ daemon_init (Daemon *daemon) GUINT_TO_POINTER (TRUE)); } + daemon->priv->admin_users = NULL; + daemon->priv->shadow_users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); 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 +890,15 @@ daemon_init (Daemon *daemon) &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 +946,8 @@ daemon_finalize (GObject *object) 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->shadow_users); g_hash_table_destroy (daemon->priv->users); G_OBJECT_CLASS (daemon_parent_class)->finalize (object); @@ -1049,7 +1278,7 @@ daemon_create_user_authorized_cb (Daemon } 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"); diff -Naurp accountsservice-0.6.15/src/daemon.h accountsservice-0.6.15.limit/src/daemon.h --- accountsservice-0.6.15/src/daemon.h 2011-10-18 01:26:32.000000000 +0530 +++ accountsservice-0.6.15.limit/src/daemon.h 2013-01-28 14:17:07.677877836 +0530 @@ -78,6 +78,13 @@ User *daemon_local_find_user_by_name (Da 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); +PasswordMode daemon_local_password_type (Daemon *daemon, + const gchar *name, + const gchar *passwd, + gboolean *locked); typedef void (*AuthorizedCallback) (Daemon *daemon, User *user, diff -Naurp accountsservice-0.6.15/src/user.c accountsservice-0.6.15.limit/src/user.c --- accountsservice-0.6.15/src/user.c 2013-01-28 15:18:41.000000000 +0530 +++ accountsservice-0.6.15.limit/src/user.c 2013-01-28 14:17:07.677877836 +0530 @@ -29,9 +29,6 @@ #include #include #include -#ifdef HAVE_SHADOW_H -#include -#endif #include #include @@ -542,12 +539,8 @@ void user_local_update_from_pwent (User *user, struct passwd *pwent) { -#ifdef HAVE_SHADOW_H - struct spwd *spent; -#endif gchar *real_name; gboolean changed; - const gchar *passwd; gboolean locked; PasswordMode mode; @@ -608,7 +601,13 @@ user_local_update_from_pwent (User /* GID */ user->gid = pwent->pw_gid; +#if 1 +#warning testing code +//#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) { @@ -634,19 +633,7 @@ user_local_update_from_pwent (User g_object_notify (G_OBJECT (user), "shell"); } - passwd = pwent->pw_passwd; -#ifdef HAVE_SHADOW_H - spent = getspnam (pwent->pw_name); - if (spent) - passwd = spent->sp_pwdp; -#endif - - if (passwd && passwd[0] == '!') { - locked = TRUE; - } - else { - locked = FALSE; - } + mode = daemon_local_password_type (user->daemon, user->user_name, pwent->pw_passwd, &locked); if (user->locked != locked) { user->locked = locked; @@ -654,21 +641,6 @@ user_local_update_from_pwent (User g_object_notify (G_OBJECT (user), "locked"); } - if (passwd[0] == 0) { - mode = PASSWORD_MODE_NONE; - } - else { - mode = PASSWORD_MODE_REGULAR; - } - -#ifdef HAVE_SHADOW_H - if (spent) { - if (spent->sp_lstchg == 0) { - mode = PASSWORD_MODE_SET_AT_LOGIN; - } - } -#endif - if (user->password_mode != mode) { user->password_mode = mode; changed = TRUE; @@ -1543,32 +1515,6 @@ out: return ret; } -static gboolean -user_HOME_available (User *user) -{ - GDir* homedir = g_dir_open (user->home_dir, 0, NULL); - - if (homedir == NULL) // HOME not found - return FALSE; - else { - const char *entry, *path_to_entry; - do { - entry = g_dir_read_name (homedir); - path_to_entry = g_build_path ("/", user->home_dir, entry, NULL); - if (g_file_test (path_to_entry, G_FILE_TEST_IS_SYMLINK)) - continue; - if (g_strcmp0 (entry, NULL) == 0) { // HOME contains only symlinks - g_dir_close (homedir); - return FALSE; - } else - break; - } while (TRUE); - } - - g_dir_close (homedir); - return TRUE; -} - static void user_change_language_authorized_cb (Daemon *daemon, User *user, @@ -1584,7 +1530,8 @@ user_change_language_authorized_cb (Daem gchar *dummy; gchar *profile_formats; - if (!user_HOME_available (user)) { + gchar *profile_path = g_build_path ("/", user->home_dir, ".profile", NULL); + if (!g_file_test (profile_path, G_FILE_TEST_IS_REGULAR)) { /* SetLanguage was probably called from a login greeter, and HOME not mounted and/or not decrypted. @@ -1671,6 +1618,7 @@ out1: } out2: + g_free (profile_path); dbus_g_method_return (context); }