--- /home/ubuntu/rpmbuild/BUILD/accountsservice-0.6.30/src/user.c +++ /home/ubuntu/rpmbuild/BUILD/accountsservice-0.6.30.limit/src/user.c @@ -111,51 +111,12 @@ G_DEFINE_TYPE_WITH_CODE (User, user, ACCOUNTS_TYPE_USER_SKELETON, G_IMPLEMENT_INTERFACE (ACCOUNTS_TYPE_USER, user_accounts_user_iface_init)); -static gint -account_type_from_pwent (struct passwd *pwent) -{ - struct group *grp; - gid_t wheel; - gid_t *groups; - gint ngroups; - gint i; - - if (pwent->pw_uid == 0) { - g_debug ("user is root so account type is administrator"); - return ACCOUNT_TYPE_ADMINISTRATOR; - } - - grp = getgrnam ("wheel"); - if (grp == NULL) { - g_debug ("wheel group not found"); - return ACCOUNT_TYPE_STANDARD; - } - wheel = grp->gr_gid; - - ngroups = get_user_groups (pwent->pw_name, pwent->pw_gid, &groups); - - for (i = 0; i < ngroups; i++) { - if (groups[i] == wheel) { - g_free (groups); - return ACCOUNT_TYPE_ADMINISTRATOR; - } - } - - g_free (groups); - - return ACCOUNT_TYPE_STANDARD; -} - void user_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; @@ -216,7 +177,10 @@ /* GID */ user->gid = pwent->pw_gid; - user->account_type = account_type_from_pwent (pwent); +#warning specific to local users, may need if else with act_from_pwent/ get_user_groups + user->account_type = daemon_local_user_type (user->daemon, + user->user_name, + user->uid); /* Username */ if (g_strcmp0 (user->user_name, pwent->pw_name) != 0) { @@ -244,40 +208,14 @@ 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; - } + /* account type */ + mode = daemon_local_password_type (user->daemon, user->user_name, pwent->pw_passwd, &locked); if (user->locked != locked) { user->locked = locked; changed = TRUE; g_object_notify (G_OBJECT (user), "locked"); } - - if (passwd && passwd[0] != 0) { - mode = PASSWORD_MODE_REGULAR; - } - else { - mode = PASSWORD_MODE_NONE; - } - -#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; --- /home/ubuntu/rpmbuild/BUILD/accountsservice-0.6.30/src/daemon.h +++ /home/ubuntu/rpmbuild/BUILD/accountsservice-0.6.30.limit/src/daemon.h @@ -78,6 +78,13 @@ gboolean daemon_local_user_is_excluded (Daemon *daemon, const gchar *name, const gchar *shell); +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, --- /home/ubuntu/rpmbuild/BUILD/accountsservice-0.6.30/src/daemon.c +++ /home/ubuntu/rpmbuild/BUILD/accountsservice-0.6.30.limit/src/daemon.c @@ -28,6 +28,10 @@ #include #include #include +#include +#ifdef HAVE_SHADOW_H +#include +#endif #include #include #include @@ -46,6 +50,7 @@ #include "util.h" #define PATH_PASSWD "/etc/passwd" +#define PATH_GROUP "/etc/group" #define PATH_SHADOW "/etc/shadow" #define PATH_NOLOGIN "/sbin/nologin" #define PATH_FALSE "/bin/false" @@ -90,11 +95,14 @@ GDBusProxy *bus_proxy; GHashTable *users; + GHashTable *shadow_users; + GList *admin_users; GHashTable *exclusions; User *autologin; GFileMonitor *passwd_monitor; + GFileMonitor *group_monitor; GFileMonitor *shadow_monitor; GFileMonitor *gdm_monitor; @@ -204,6 +212,151 @@ return ret; } +/* optimize shadow and group file read */ +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) +{ +#ifdef HAVE_SHADOW_H +#warning testing code + 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 HAVE_SHADOW_H +#warning testing code + 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) +{ +#warning testing code + int i; + FILE *fp; + gid_t wheel; + struct group *grpent; + + g_list_free_full (daemon->priv->admin_users, g_free); + + grpent = getgrnam ("wheel"); + if (grpent == NULL) { + g_debug ("wheel group not found"); + return; + } + wheel = 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; + } + + /* using a list as no of admin users on a system is expected to be low */ + while ((grpent = fgetgrent(fp)) != NULL ) { + if ( grpent->gr_gid == wheel) { + 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); +} + #ifdef HAVE_UTMPX_H typedef struct { @@ -227,6 +380,7 @@ entry_generator_wtmp (GHashTable *users, gpointer *state) { +#warning fix this to ignore call to duplicate entries GHashTable *login_hash, *logout_hash; struct utmpx *wtmp_entry; GHashTableIter iter; @@ -290,6 +444,7 @@ continue; } + g_warning ("pw %s\n", wtmp_entry->ut_user); pwent = getpwnam (wtmp_entry->ut_user); if (pwent == NULL) { continue; @@ -438,6 +593,7 @@ g_free (filename); if (regular) { + g_warning ("pw %s\n", name); pwent = getpwnam (name); if (pwent == NULL) g_debug ("user '%s' in cache dir but not present on system", name); @@ -528,6 +684,11 @@ GHashTableIter iter; gpointer name; User *user; + gint64 time = g_get_monotonic_time (); + + /* Update password type and mode of local users */ + reload_group (daemon); + reload_shadow (daemon); /* Track the users that we saw during our (re)load */ users = create_users_hash_table (); @@ -584,6 +745,9 @@ } g_hash_table_destroy (old_users); + + time = g_get_monotonic_time () - time; + g_warning ("done %" G_GINT64_FORMAT " \n", time); } static gboolean @@ -655,7 +819,7 @@ /* we wait half a second or so in case /etc/passwd and * /etc/shadow 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 @@ -729,12 +893,23 @@ } daemon->priv->users = create_users_hash_table (); + daemon->priv->admin_users = NULL; + daemon->priv->shadow_users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_free); file = g_file_new_for_path (PATH_PASSWD); daemon->priv->passwd_monitor = g_file_monitor_file (file, G_FILE_MONITOR_NONE, NULL, &error); + g_object_unref (file); + 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_SHADOW); daemon->priv->shadow_monitor = g_file_monitor_file (file, @@ -756,6 +931,15 @@ daemon); } else { g_warning ("Unable to monitor %s: %s", PATH_PASSWD, error->message); + g_error_free (error); + } + if (daemon->priv->group_monitor != NULL) { + g_signal_connect (daemon->priv->group_monitor, + "changed", + G_CALLBACK (on_passwd_monitor_changed), + daemon); + } else { + g_warning ("Unable to monitor %s: %s", PATH_GROUP, error->message); g_error_free (error); } if (daemon->priv->shadow_monitor != NULL) { @@ -796,6 +980,8 @@ if (daemon->priv->bus_connection != NULL) g_object_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);