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