|
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)
|