Blame grp/grp-merge.c

Packit 6c4009
/* Group merging implementation.
Packit 6c4009
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <grp.h>
Packit 6c4009
#include <grp-merge.h>
Packit 6c4009
Packit 6c4009
#define BUFCHECK(size)			\
Packit 6c4009
  ({					\
Packit 6c4009
    do					\
Packit 6c4009
      {					\
Packit 6c4009
	if (c + (size) > buflen)	\
Packit 6c4009
          {				\
Packit 6c4009
	    free (members);		\
Packit 6c4009
	    return ERANGE;		\
Packit 6c4009
	  }				\
Packit 6c4009
      }					\
Packit 6c4009
    while (0);				\
Packit 6c4009
  })
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__copy_grp (const struct group srcgrp, const size_t buflen,
Packit 6c4009
	    struct group *destgrp, char *destbuf, char **endptr)
Packit 6c4009
{
Packit 6c4009
  size_t i;
Packit 6c4009
  size_t c = 0;
Packit 6c4009
  size_t len;
Packit 6c4009
  size_t memcount;
Packit 6c4009
  char **members = NULL;
Packit 6c4009
Packit 6c4009
  /* Copy the GID.  */
Packit 6c4009
  destgrp->gr_gid = srcgrp.gr_gid;
Packit 6c4009
Packit 6c4009
  /* Copy the name.  */
Packit 6c4009
  len = strlen (srcgrp.gr_name) + 1;
Packit 6c4009
  BUFCHECK (len);
Packit 6c4009
  memcpy (&destbuf[c], srcgrp.gr_name, len);
Packit 6c4009
  destgrp->gr_name = &destbuf[c];
Packit 6c4009
  c += len;
Packit 6c4009
Packit 6c4009
  /* Copy the password.  */
Packit 6c4009
  len = strlen (srcgrp.gr_passwd) + 1;
Packit 6c4009
  BUFCHECK (len);
Packit 6c4009
  memcpy (&destbuf[c], srcgrp.gr_passwd, len);
Packit 6c4009
  destgrp->gr_passwd = &destbuf[c];
Packit 6c4009
  c += len;
Packit 6c4009
Packit 6c4009
  /* Count all of the members.  */
Packit 6c4009
  for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
Packit 6c4009
    ;
Packit 6c4009
Packit 6c4009
  /* Allocate a temporary holding area for the pointers to the member
Packit 6c4009
     contents, including space for a NULL-terminator.  */
Packit 6c4009
  members = malloc (sizeof (char *) * (memcount + 1));
Packit 6c4009
  if (members == NULL)
Packit 6c4009
    return ENOMEM;
Packit 6c4009
Packit 6c4009
  /* Copy all of the group members to destbuf and add a pointer to each of
Packit 6c4009
     them into the 'members' array.  */
Packit 6c4009
  for (i = 0; srcgrp.gr_mem[i]; i++)
Packit 6c4009
    {
Packit 6c4009
      len = strlen (srcgrp.gr_mem[i]) + 1;
Packit 6c4009
      BUFCHECK (len);
Packit 6c4009
      memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
Packit 6c4009
      members[i] = &destbuf[c];
Packit 6c4009
      c += len;
Packit 6c4009
    }
Packit 6c4009
  members[i] = NULL;
Packit 6c4009
Packit 6c4009
  /* Align for pointers.  We can't simply align C because we need to
Packit 6c4009
     align destbuf[c].  */
Packit 6c4009
  if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
Packit 6c4009
    {
Packit 6c4009
      uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
Packit 6c4009
      c += __alignof__(char **) - mis_align;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Copy the pointers from the members array into the buffer and assign them
Packit 6c4009
     to the gr_mem member of destgrp.  */
Packit 6c4009
  destgrp->gr_mem = (char **) &destbuf[c];
Packit 6c4009
  len = sizeof (char *) * (memcount + 1);
Packit 6c4009
  BUFCHECK (len);
Packit 6c4009
  memcpy (&destbuf[c], members, len);
Packit 6c4009
  c += len;
Packit 6c4009
  free (members);
Packit 6c4009
  members = NULL;
Packit 6c4009
Packit 6c4009
  /* Save the count of members at the end.  */
Packit 6c4009
  BUFCHECK (sizeof (size_t));
Packit 6c4009
  memcpy (&destbuf[c], &memcount, sizeof (size_t));
Packit 6c4009
  c += sizeof (size_t);
Packit 6c4009
Packit 6c4009
  if (endptr)
Packit 6c4009
    *endptr = destbuf + c;
Packit 6c4009
  return 0;
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__copy_grp)
Packit 6c4009
Packit 6c4009
/* Check that the name, GID and passwd fields match, then
Packit 6c4009
   copy in the gr_mem array.  */
Packit 6c4009
int
Packit 6c4009
__merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
Packit 6c4009
	     size_t buflen, struct group *mergegrp, char *mergebuf)
Packit 6c4009
{
Packit 6c4009
  size_t c, i, len;
Packit 6c4009
  size_t savedmemcount;
Packit 6c4009
  size_t memcount;
Packit 6c4009
  size_t membersize;
Packit 6c4009
  char **members = NULL;
Packit 6c4009
Packit 6c4009
  /* We only support merging members of groups with identical names and
Packit 6c4009
     GID values. If we hit this case, we need to overwrite the current
Packit 6c4009
     buffer with the saved one (which is functionally equivalent to
Packit 6c4009
     treating the new lookup as NSS_STATUS_NOTFOUND).  */
Packit 6c4009
  if (mergegrp->gr_gid != savedgrp->gr_gid
Packit 6c4009
      || strcmp (mergegrp->gr_name, savedgrp->gr_name))
Packit 6c4009
    return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
Packit 6c4009
Packit 6c4009
  /* Get the count of group members from the last sizeof (size_t) bytes in the
Packit 6c4009
     mergegrp buffer.  */
Packit 6c4009
  savedmemcount = *(size_t *) (savedend - sizeof (size_t));
Packit 6c4009
Packit 6c4009
  /* Get the count of new members to add.  */
Packit 6c4009
  for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
Packit 6c4009
    ;
Packit 6c4009
Packit 6c4009
  /* Create a temporary array to hold the pointers to the member values from
Packit 6c4009
     both the saved and merge groups.  */
Packit 6c4009
  membersize = savedmemcount + memcount + 1;
Packit 6c4009
  members = malloc (sizeof (char *) * membersize);
Packit 6c4009
  if (members == NULL)
Packit 6c4009
    return ENOMEM;
Packit 6c4009
Packit 6c4009
  /* Copy in the existing member pointers from the saved group
Packit 6c4009
     Note: this is not NULL-terminated yet.  */
Packit 6c4009
  memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
Packit 6c4009
Packit 6c4009
  /* Back up into the savedbuf until we get back to the NULL-terminator of the
Packit 6c4009
     group member list. (This means walking back savedmemcount + 1 (char *) pointers
Packit 6c4009
     and the member count value.
Packit 6c4009
     The value of c is going to be the used length of the buffer backed up by
Packit 6c4009
     the member count and further backed up by the size of the pointers.  */
Packit 6c4009
  c = savedend - savedbuf
Packit 6c4009
      - sizeof (size_t)
Packit 6c4009
      - sizeof (char *) * (savedmemcount + 1);
Packit 6c4009
Packit 6c4009
  /* Add all the new group members, overwriting the old NULL-terminator while
Packit 6c4009
     adding the new pointers to the temporary array.  */
Packit 6c4009
  for (i = 0; mergegrp->gr_mem[i]; i++)
Packit 6c4009
    {
Packit 6c4009
      len = strlen (mergegrp->gr_mem[i]) + 1;
Packit 6c4009
      BUFCHECK (len);
Packit 6c4009
      memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
Packit 6c4009
      members[savedmemcount + i] = &savedbuf[c];
Packit 6c4009
      c += len;
Packit 6c4009
    }
Packit 6c4009
  /* Add the NULL-terminator.  */
Packit 6c4009
  members[savedmemcount + memcount] = NULL;
Packit 6c4009
Packit 6c4009
  /* Align for pointers.  We can't simply align C because we need to
Packit 6c4009
     align savedbuf[c].  */
Packit 6c4009
  if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
Packit 6c4009
    {
Packit 6c4009
      uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
Packit 6c4009
      c += __alignof__(char **) - mis_align;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Copy the member array back into the buffer after the member list and free
Packit 6c4009
     the member array.  */
Packit 6c4009
  savedgrp->gr_mem = (char **) &savedbuf[c];
Packit 6c4009
  len = sizeof (char *) * membersize;
Packit 6c4009
  BUFCHECK (len);
Packit 6c4009
  memcpy (&savedbuf[c], members, len);
Packit 6c4009
  c += len;
Packit 6c4009
Packit 6c4009
  free (members);
Packit 6c4009
  members = NULL;
Packit 6c4009
Packit 6c4009
  /* Finally, copy the results back into mergebuf, since that's the buffer
Packit 6c4009
     that we were provided by the caller.  */
Packit 6c4009
  return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
Packit 6c4009
}
Packit 6c4009
libc_hidden_def (__merge_grp)