(root)/
glibc-2.38/
grp/
grp-merge.c
       1  /* Group merging implementation.
       2     Copyright (C) 2016-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <errno.h>
      20  #include <stdlib.h>
      21  #include <string.h>
      22  #include <grp.h>
      23  #include <grp-merge.h>
      24  
      25  #define BUFCHECK(size)			\
      26    ({					\
      27      do					\
      28        {					\
      29  	if (c + (size) > buflen)	\
      30            {				\
      31  	    free (members);		\
      32  	    return ERANGE;		\
      33  	  }				\
      34        }					\
      35      while (0);				\
      36    })
      37  
      38  int
      39  __copy_grp (const struct group srcgrp, const size_t buflen,
      40  	    struct group *destgrp, char *destbuf, char **endptr)
      41  {
      42    size_t i;
      43    size_t c = 0;
      44    size_t len;
      45    size_t memcount;
      46    char **members = NULL;
      47  
      48    /* Copy the GID.  */
      49    destgrp->gr_gid = srcgrp.gr_gid;
      50  
      51    /* Copy the name.  */
      52    len = strlen (srcgrp.gr_name) + 1;
      53    BUFCHECK (len);
      54    memcpy (&destbuf[c], srcgrp.gr_name, len);
      55    destgrp->gr_name = &destbuf[c];
      56    c += len;
      57  
      58    /* Copy the password.  */
      59    len = strlen (srcgrp.gr_passwd) + 1;
      60    BUFCHECK (len);
      61    memcpy (&destbuf[c], srcgrp.gr_passwd, len);
      62    destgrp->gr_passwd = &destbuf[c];
      63    c += len;
      64  
      65    /* Count all of the members.  */
      66    for (memcount = 0; srcgrp.gr_mem[memcount]; memcount++)
      67      ;
      68  
      69    /* Allocate a temporary holding area for the pointers to the member
      70       contents, including space for a NULL-terminator.  */
      71    members = malloc (sizeof (char *) * (memcount + 1));
      72    if (members == NULL)
      73      return ENOMEM;
      74  
      75    /* Copy all of the group members to destbuf and add a pointer to each of
      76       them into the 'members' array.  */
      77    for (i = 0; srcgrp.gr_mem[i]; i++)
      78      {
      79        len = strlen (srcgrp.gr_mem[i]) + 1;
      80        BUFCHECK (len);
      81        memcpy (&destbuf[c], srcgrp.gr_mem[i], len);
      82        members[i] = &destbuf[c];
      83        c += len;
      84      }
      85    members[i] = NULL;
      86  
      87    /* Align for pointers.  We can't simply align C because we need to
      88       align destbuf[c].  */
      89    if ((((uintptr_t)destbuf + c) & (__alignof__(char **) - 1)) != 0)
      90      {
      91        uintptr_t mis_align = ((uintptr_t)destbuf + c) & (__alignof__(char **) - 1);
      92        c += __alignof__(char **) - mis_align;
      93      }
      94  
      95    /* Copy the pointers from the members array into the buffer and assign them
      96       to the gr_mem member of destgrp.  */
      97    destgrp->gr_mem = (char **) &destbuf[c];
      98    len = sizeof (char *) * (memcount + 1);
      99    BUFCHECK (len);
     100    memcpy (&destbuf[c], members, len);
     101    c += len;
     102    free (members);
     103    members = NULL;
     104  
     105    /* Save the count of members at the end.  */
     106    BUFCHECK (sizeof (size_t));
     107    memcpy (&destbuf[c], &memcount, sizeof (size_t));
     108    c += sizeof (size_t);
     109  
     110    if (endptr)
     111      *endptr = destbuf + c;
     112    return 0;
     113  }
     114  libc_hidden_def (__copy_grp)
     115  
     116  /* Check that the name, GID and passwd fields match, then
     117     copy in the gr_mem array.  */
     118  int
     119  __merge_grp (struct group *savedgrp, char *savedbuf, char *savedend,
     120  	     size_t buflen, struct group *mergegrp, char *mergebuf)
     121  {
     122    size_t c, i, len;
     123    size_t savedmemcount;
     124    size_t memcount;
     125    size_t membersize;
     126    char **members = NULL;
     127  
     128    /* We only support merging members of groups with identical names and
     129       GID values. If we hit this case, we need to overwrite the current
     130       buffer with the saved one (which is functionally equivalent to
     131       treating the new lookup as NSS_STATUS_NOTFOUND).  */
     132    if (mergegrp->gr_gid != savedgrp->gr_gid
     133        || strcmp (mergegrp->gr_name, savedgrp->gr_name))
     134      return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
     135  
     136    /* Get the count of group members from the last sizeof (size_t) bytes in the
     137       mergegrp buffer.  */
     138    savedmemcount = *(size_t *) (savedend - sizeof (size_t));
     139  
     140    /* Get the count of new members to add.  */
     141    for (memcount = 0; mergegrp->gr_mem[memcount]; memcount++)
     142      ;
     143  
     144    /* Create a temporary array to hold the pointers to the member values from
     145       both the saved and merge groups.  */
     146    membersize = savedmemcount + memcount + 1;
     147    members = malloc (sizeof (char *) * membersize);
     148    if (members == NULL)
     149      return ENOMEM;
     150  
     151    /* Copy in the existing member pointers from the saved group
     152       Note: this is not NULL-terminated yet.  */
     153    memcpy (members, savedgrp->gr_mem, sizeof (char *) * savedmemcount);
     154  
     155    /* Back up into the savedbuf until we get back to the NULL-terminator of the
     156       group member list. (This means walking back savedmemcount + 1 (char *) pointers
     157       and the member count value.
     158       The value of c is going to be the used length of the buffer backed up by
     159       the member count and further backed up by the size of the pointers.  */
     160    c = savedend - savedbuf
     161        - sizeof (size_t)
     162        - sizeof (char *) * (savedmemcount + 1);
     163  
     164    /* Add all the new group members, overwriting the old NULL-terminator while
     165       adding the new pointers to the temporary array.  */
     166    for (i = 0; mergegrp->gr_mem[i]; i++)
     167      {
     168        len = strlen (mergegrp->gr_mem[i]) + 1;
     169        BUFCHECK (len);
     170        memcpy (&savedbuf[c], mergegrp->gr_mem[i], len);
     171        members[savedmemcount + i] = &savedbuf[c];
     172        c += len;
     173      }
     174    /* Add the NULL-terminator.  */
     175    members[savedmemcount + memcount] = NULL;
     176  
     177    /* Align for pointers.  We can't simply align C because we need to
     178       align savedbuf[c].  */
     179    if ((((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1)) != 0)
     180      {
     181        uintptr_t mis_align = ((uintptr_t)savedbuf + c) & (__alignof__(char **) - 1);
     182        c += __alignof__(char **) - mis_align;
     183      }
     184  
     185    /* Copy the member array back into the buffer after the member list and free
     186       the member array.  */
     187    savedgrp->gr_mem = (char **) &savedbuf[c];
     188    len = sizeof (char *) * membersize;
     189    BUFCHECK (len);
     190    memcpy (&savedbuf[c], members, len);
     191    c += len;
     192  
     193    free (members);
     194    members = NULL;
     195  
     196    /* Finally, copy the results back into mergebuf, since that's the buffer
     197       that we were provided by the caller.  */
     198    return __copy_grp (*savedgrp, buflen, mergegrp, mergebuf, NULL);
     199  }
     200  libc_hidden_def (__merge_grp)