[Bug 249445] sysutils/accountsservice: Update to 0.6.55

From: <bugzilla-noreply_at_freebsd.org>
Date: Sat, 26 Jun 2021 22:45:43 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=249445

david@dcrosstech.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |david@dcrosstech.com

--- Comment #12 from david@dcrosstech.com ---
I have been hitting this issue myself, and I think the bug exists in 2 places. 
1 in accountservice/src/daemon.c:

daemon.c:197
>         /* First iteration */
>         if (*state == NULL) {
>                 GHashTable *shadow_users = NULL;
>                 FILE *fp;
> #ifdef HAVE_SHADOW_H
>                 struct spwd *shadow_entry;
> 
>                 fp = fopen (PATH_SHADOW, "r");
>                 if (fp == NULL) {
>                         g_warning ("Unable to open %s: %s", PATH_SHADOW, g_strerror (errno));
>                         return NULL;
>                 }
> 
>                 shadow_users = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
> 
>                 do {
>                         int ret = 0;
> 
>                         shadow_entry_buffers = g_malloc0 (sizeof (*shadow_entry_buffers));
> 
>                         ret = fgetspent_r (fp, &shadow_entry_buffers->spbuf, shadow_entry_buffers->buf, sizeof (shadow_entry_buffers->buf), &shadow_entry);
>                         if (ret == 0) {
>                                 g_hash_table_insert (shadow_users, g_strdup (shadow_entry->sp_namp), shadow_entry_buffers);
>                         } else {
>                                 g_free (shadow_entry_buffers);
> 
>                                 if (errno != EINTR) {
>                                         break;
>                                 }
>                         }
>                 } while (shadow_entry != NULL);
> 
>                 fclose (fp);
> 
>                 if (g_hash_table_size (shadow_users) == 0) {
>                         g_clear_pointer (&shadow_users, g_hash_table_unref);
>                         return NULL;
>                 }
> #endif
> 
>                 fp = fopen (PATH_PASSWD, "r");
>                 if (fp == NULL) {
>                         g_clear_pointer (&shadow_users, g_hash_table_unref);
>                         g_warning ("Unable to open %s: %s", PATH_PASSWD, g_strerror (errno));
>                         return NULL;
>                 }
> 
>                 generator_state = g_malloc0 (sizeof (*generator_state));
>                 generator_state->fp = fp;
>                 generator_state->users = shadow_users;
> 
>                 *state = generator_state;
>         }
> 
>         /* Every iteration */
>         generator_state = *state;
> 
>         if (g_hash_table_size (users) < MAX_LOCAL_USERS) {
>                 pwent = fgetpwent (generator_state->fp);
>                 if (pwent != NULL) {
> #ifdef HAVE_SHADOW_H
>                         shadow_entry_buffers = g_hash_table_lookup (generator_state->users, pwent->pw_name);
> 
>                         if (shadow_entry_buffers != NULL) {
>                             *spent = &shadow_entry_buffers->spbuf;
>                         }
>                         return pwent;
> #else
>                         if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name))
>                             return pwent;
> #endif
>                 }
>         }


Note that my reading of the code is that it pulls all of /etc/shadow into
memory (and does it extremely hamfistedly), and then uses that to prune
/etc/passwd in such a way that users that aren't in /etc/shadow don't even show
up:
>    if (!generator_state->users || g_hash_table_lookup (generator_state->users, pwent->pw_name))
>        return pwent;

So generator_state-> users has to be non-null, AND it has to have a user by
that name in it... but in the first iteration generator_state->users is set to
shadow_users (L246), however shadow_users is set L210 (inside the #ifdef
block), and populated in that block, what WE get is the initial value (NULL),
L199.... Therefore that check NEVER passes, and we never have ANY users.

So I fixed that by removing the if conditional and always returned pwent.

This however did not fix it.  In experimenting I would swap out JUST
account-daemon (or whatever it is called), and hit gdm.  THIS worked.... and
later I discovered that there is libaccountservice at play here,  I think there
is a *second* bug lurking in there.  I did a git diff between the two versions
that we upgraded and .. a lot changed.  

I am not done investigating yet, but I figured more eyes will help.  I hope
this helps.

-- 
You are receiving this mail because:
You are the assignee for the bug.