(root)/
glibc-2.38/
nss/
nss_db/
db-initgroups.c
       1  /* Initgroups handling in nss_db module.
       2     Copyright (C) 2011-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 Library General Public License as
       7     published by the Free Software Foundation; either version 2 of the
       8     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     Library General Public License for more details.
      14  
      15     You should have received a copy of the GNU Library General Public
      16     License along with the GNU C Library; see the file COPYING.LIB.  If
      17     not, see <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <ctype.h>
      20  #include <errno.h>
      21  #include <grp.h>
      22  #include <limits.h>
      23  #include <paths.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <stdint.h>
      27  #include <sys/param.h>
      28  
      29  #include "nss_db.h"
      30  
      31  /* The hashing function we use.  */
      32  #include "../intl/hash-string.h"
      33  
      34  enum nss_status
      35  _nss_db_initgroups_dyn (const char *user, gid_t group, long int *start,
      36  			long int *size, gid_t **groupsp, long int limit,
      37  			int *errnop)
      38  {
      39    struct nss_db_map state = { NULL, 0 };
      40    enum nss_status status = internal_setent (_PATH_VARDB "group.db", &state);
      41    if (status != NSS_STATUS_SUCCESS)
      42      {
      43        *errnop = errno;
      44        return status;
      45      }
      46  
      47    const struct nss_db_header *header = state.header;
      48    int i;
      49    for (i = 0; i < header->ndbs; ++i)
      50      if (header->dbs[i].id == ':')
      51        break;
      52    if (i == header->ndbs)
      53      {
      54        status = NSS_STATUS_UNAVAIL;
      55        goto out;
      56      }
      57  
      58    const stridx_t *hashtable
      59      = (const stridx_t *) ((const char *) header
      60  			  + header->dbs[i].hashoffset);
      61    const char *valstrtab = (const char *) header + header->valstroffset;
      62    size_t userlen = strlen (user);
      63    uint32_t hashval = __hash_string (user);
      64    size_t hidx = hashval % header->dbs[i].hashsize;
      65    size_t hval2 = 1 + hashval % (header->dbs[i].hashsize - 2);
      66  
      67    gid_t *groups = *groupsp;
      68  
      69    status = NSS_STATUS_NOTFOUND;
      70    while (hashtable[hidx] != ~((stridx_t) 0))
      71      {
      72        const char *valstr = valstrtab + hashtable[hidx];
      73        while (isblank (*valstr))
      74  	++valstr;
      75  
      76        if (strncmp (valstr, user, userlen) == 0 && isblank (valstr[userlen]))
      77  	{
      78  	  valstr += userlen + 1;
      79  	  while (isblank (*valstr))
      80  	    ++valstr;
      81  
      82  	  while (*valstr != '\0')
      83  	    {
      84  	      errno = 0;
      85  	      char *endp;
      86  	      unsigned long int n = strtoul (valstr, &endp, 10);
      87  	      if (*endp != ',' && *endp != '\0')
      88  		break;
      89  	      valstr = *endp == '\0' ? endp : endp + 1;
      90  
      91  	      if (n != ULONG_MAX || errno != ERANGE)
      92  		{
      93  		  /* Insert the group.  */
      94  		  if (*start == *size)
      95  		    {
      96  		      /* Need a bigger buffer.  */
      97  		      if (limit > 0 && *size == limit)
      98  			{
      99  			  /* We reached the maximum.  */
     100  			  status = NSS_STATUS_SUCCESS;
     101  			  goto out;
     102  			}
     103  
     104  		      long int newsize;
     105  		      if (limit <= 0)
     106  			newsize = 2 * *size;
     107  		      else
     108  			newsize = MIN (limit, 2 * *size);
     109  
     110  		      gid_t *newgroups = realloc (groups,
     111  						  newsize * sizeof (*groups));
     112  		      if (newgroups == NULL)
     113  			{
     114  			  *errnop = ENOMEM;
     115  			  status = NSS_STATUS_TRYAGAIN;
     116  			  goto out;
     117  			}
     118  
     119  		      *groupsp = groups = newgroups;
     120  		      *size = newsize;
     121  		    }
     122  
     123  		  groups[*start] = n;
     124  		  *start += 1;
     125  		}
     126  	    }
     127  
     128  	  status = NSS_STATUS_SUCCESS;
     129  	  break;
     130  	}
     131  
     132        if ((hidx += hval2) >= header->dbs[i].hashsize)
     133  	hidx -= header->dbs[i].hashsize;
     134      }
     135  
     136   out:
     137    internal_endent (&state);
     138  
     139    return status;
     140  }