Blame grp/grp-merge.c

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