(root)/
glibc-2.38/
nss/
nss_files/
files-initgroups.c
       1  /* Initgroups handling in nss_files 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 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 <grp.h>
      21  #include <nss.h>
      22  #include <stdio_ext.h>
      23  #include <string.h>
      24  #include <sys/param.h>
      25  #include <stdbool.h>
      26  #include <stdlib.h>
      27  #include <scratch_buffer.h>
      28  #include <nss.h>
      29  #include <nss_files.h>
      30  
      31  enum nss_status
      32  _nss_files_initgroups_dyn (const char *user, gid_t group, long int *start,
      33  			   long int *size, gid_t **groupsp, long int limit,
      34  			   int *errnop)
      35  {
      36    FILE *stream = __nss_files_fopen ("/etc/group");
      37    if (stream == NULL)
      38      {
      39        *errnop = errno;
      40        return *errnop == ENOMEM ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
      41      }
      42  
      43    char *line = NULL;
      44    size_t linelen = 0;
      45    enum nss_status status = NSS_STATUS_SUCCESS;
      46    bool any = false;
      47  
      48    struct scratch_buffer tmpbuf;
      49    scratch_buffer_init (&tmpbuf);
      50  
      51    gid_t *groups = *groupsp;
      52  
      53    /* We have to iterate over the entire file.  */
      54    while (1)
      55      {
      56        fpos_t pos;
      57        fgetpos (stream, &pos);
      58        ssize_t n = __getline (&line, &linelen, stream);
      59        if (n < 0)
      60  	{
      61  	  if (! __feof_unlocked (stream))
      62  	    status = ((*errnop = errno) == ENOMEM
      63  		      ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL);
      64  	  break;
      65  	}
      66  
      67        struct group grp;
      68        int res = _nss_files_parse_grent (line, &grp,
      69  					tmpbuf.data, tmpbuf.length, errnop);
      70        if (res == -1)
      71  	{
      72  	  if (!scratch_buffer_grow (&tmpbuf))
      73  	    {
      74  	      *errnop = ENOMEM;
      75  	      status = NSS_STATUS_TRYAGAIN;
      76  	      goto out;
      77  	    }
      78  	  /* Reread current line, the parser has clobbered it.  */
      79  	  fsetpos (stream, &pos);
      80  	  continue;
      81  	}
      82  
      83        if (res > 0 && grp.gr_gid != group)
      84  	for (char **m = grp.gr_mem; *m != NULL; ++m)
      85  	  if (strcmp (*m, user) == 0)
      86  	    {
      87  	      /* Matches user.  Insert this group.  */
      88  	      if (*start == *size)
      89  		{
      90  		  /* Need a bigger buffer.  */
      91  		  if (limit > 0 && *size == limit)
      92  		    /* We reached the maximum.  */
      93  		    goto out;
      94  
      95  		  long int newsize;
      96  		  if (limit <= 0)
      97  		    newsize = 2 * *size;
      98  		  else
      99  		    newsize = MIN (limit, 2 * *size);
     100  
     101  		  gid_t *newgroups = realloc (groups,
     102  					      newsize * sizeof (*groups));
     103  		  if (newgroups == NULL)
     104  		    {
     105  		      *errnop = ENOMEM;
     106  		      status = NSS_STATUS_TRYAGAIN;
     107  		      goto out;
     108  		    }
     109  		  *groupsp = groups = newgroups;
     110  		  *size = newsize;
     111  		}
     112  
     113  	      groups[*start] = grp.gr_gid;
     114  	      *start += 1;
     115  	      any = true;
     116  
     117  	      break;
     118  	    }
     119      }
     120  
     121   out:
     122    /* Free memory.  */
     123    scratch_buffer_free (&tmpbuf);
     124    free (line);
     125  
     126    fclose (stream);
     127  
     128    return status == NSS_STATUS_SUCCESS && !any ? NSS_STATUS_NOTFOUND : status;
     129  }
     130  libc_hidden_def (_nss_files_initgroups_dyn)