Exemplo n.º 1
0
Arquivo: id.c Projeto: AnthraX1/rk
static int
xgetgroups (const char *username, int *n_groups, GETGROUPS_T **groups)
{
  int max_n_groups;
  int ng;
  GETGROUPS_T *g;
  int fail = 0;

  if (username == 0)
    max_n_groups = getgroups (0, NULL);
  else
    max_n_groups = getugroups (0, NULL, username);

  /* Add 1 just in case max_n_groups is zero.  */
  g = (GETGROUPS_T *) xmalloc (max_n_groups * sizeof (GETGROUPS_T) + 1);
  if (username == 0)
    ng = getgroups (max_n_groups, g);
  else
    ng = getugroups (max_n_groups, g, username);

  if (ng < 0)
    {
      error (0, errno, _("cannot get supplemental group list"));
      ++fail;
      free (groups);
    }
  if (!fail)
    {
      *n_groups = ng;
      *groups = g;
    }
  return fail;
}
Exemplo n.º 2
0
int
mgetgroups (const char *username, gid_t gid, GETGROUPS_T **groups)
{
  int max_n_groups;
  int ng;
  GETGROUPS_T *g;

  max_n_groups = (username
		  ? getugroups (0, NULL, username, gid)
		  : getgroups (0, NULL));

  /* If we failed to count groups with NULL for a buffer,
     try again with a non-NULL one, just in case.  */
  if (max_n_groups < 0)
      max_n_groups = 5;

  if (xalloc_oversized (max_n_groups, sizeof *g))
    {
      errno = ENOMEM;
      return -1;
    }

  g = malloc (max_n_groups * sizeof *g);
  if (g == NULL)
    return -1;

  ng = (username
	? getugroups (max_n_groups, g, username, gid)
	: getgroups (max_n_groups, g));

  if (ng < 0)
    {
      int saved_errno = errno;
      free (g);
      errno = saved_errno;
      return -1;
    }

  *groups = g;
  return ng;
}
Exemplo n.º 3
0
int
mgetgroups (char const *username, gid_t gid, gid_t **groups)
{
  int max_n_groups;
  int ng;
  gid_t *g;

#if HAVE_GETGROUPLIST
  /* We prefer to use getgrouplist if available, because it has better
     performance characteristics.

     In glibc 2.3.2, getgrouplist is buggy.  If you pass a zero as the
     length of the output buffer, getgrouplist will still write to the
     buffer.  Contrary to what some versions of the getgrouplist
     manpage say, this doesn't happen with nonzero buffer sizes.
     Therefore our usage here just avoids a zero sized buffer.  */
  if (username)
    {
      enum { N_GROUPS_INIT = 10 };
      max_n_groups = N_GROUPS_INIT;

      g = realloc_groupbuf (NULL, max_n_groups);
      if (g == NULL)
        return -1;

      while (1)
        {
          gid_t *h;
          int last_n_groups = max_n_groups;

          /* getgrouplist updates max_n_groups to num required.  */
          ng = getgrouplist (username, gid, g, &max_n_groups);

          /* Some systems (like Darwin) have a bug where they
             never increase max_n_groups.  */
          if (ng < 0 && last_n_groups == max_n_groups)
            max_n_groups *= 2;

          if ((h = realloc_groupbuf (g, max_n_groups)) == NULL)
            {
              int saved_errno = errno;
              free (g);
              errno = saved_errno;
              return -1;
            }
          g = h;

          if (0 <= ng)
            {
              *groups = g;
              /* On success some systems just return 0 from getgrouplist,
                 so return max_n_groups rather than ng.  */
              return max_n_groups;
            }
        }
    }
  /* else no username, so fall through and use getgroups. */
#endif

  max_n_groups = (username
                  ? getugroups (0, NULL, username, gid)
                  : getgroups (0, NULL));

  /* If we failed to count groups because there is no supplemental
     group support, then return an array containing just GID.
     Otherwise, we fail for the same reason.  */
  if (max_n_groups < 0)
    {
      if (errno == ENOSYS && (g = realloc_groupbuf (NULL, 1)))
        {
          *groups = g;
          *g = gid;
          return gid != (gid_t) -1;
        }
      return -1;
    }

  if (max_n_groups == 0 || (!username && gid != (gid_t) -1))
    max_n_groups++;
  g = realloc_groupbuf (NULL, max_n_groups);
  if (g == NULL)
    return -1;

  ng = (username
        ? getugroups (max_n_groups, g, username, gid)
        : getgroups (max_n_groups - (gid != (gid_t) -1),
                                g + (gid != (gid_t) -1)));

  if (ng < 0)
    {
      /* Failure is unexpected, but handle it anyway.  */
      int saved_errno = errno;
      free (g);
      errno = saved_errno;
      return -1;
    }

  if (!username && gid != (gid_t) -1)
    {
      *g = gid;
      ng++;
    }
  *groups = g;

  /* Reduce the number of duplicates.  On some systems, getgroups
     returns the effective gid twice: once as the first element, and
     once in its position within the supplementary groups.  On other
     systems, getgroups does not return the effective gid at all,
     which is why we provide a GID argument.  Meanwhile, the GID
     argument, if provided, is typically any member of the
     supplementary groups, and not necessarily the effective gid.  So,
     the most likely duplicates are the first element with an
     arbitrary other element, or pair-wise duplication between the
     first and second elements returned by getgroups.  It is possible
     that this O(n) pass will not remove all duplicates, but it is not
     worth the effort to slow down to an O(n log n) algorithm that
     sorts the array in place, nor the extra memory needed for
     duplicate removal via an O(n) hash-table.  Hence, this function
     is only documented as guaranteeing no pair-wise duplicates,
     rather than returning the minimal set.  */
  if (1 < ng)
    {
      gid_t first = *g;
      gid_t *next;
      gid_t *groups_end = g + ng;

      for (next = g + 1; next < groups_end; next++)
        {
          if (*next == first || *next == *g)
            ng--;
          else
            *++g = *next;
        }
    }

  return ng;
}