(root)/
coreutils-9.4/
lib/
getugroups.c
       1  /* getugroups.c -- return a list of the groups a user is in
       2  
       3     Copyright (C) 1990-1991, 1998-2000, 2003-2023 Free Software Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file 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
      13     GNU Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Written by David MacKenzie. */
      19  
      20  #include <config.h>
      21  
      22  #include "getugroups.h"
      23  
      24  #include <errno.h>
      25  #include <limits.h>
      26  #include <stdio.h> /* grp.h on alpha OSF1 V2.0 uses "FILE *". */
      27  #include <string.h>
      28  #include <unistd.h>
      29  
      30  #if !HAVE_GRP_H || defined __ANDROID__
      31  
      32  /* Mingw lacks all things related to group management.  The best we
      33     can do is fail with ENOSYS.
      34  
      35     Bionic declares e.g. getgrent() in <grp.h> but it isn't actually
      36     defined in the library.  */
      37  
      38  int
      39  getugroups (_GL_UNUSED int maxcount,
      40              _GL_UNUSED gid_t *grouplist,
      41              _GL_UNUSED char const *username,
      42              _GL_UNUSED gid_t gid)
      43  {
      44    errno = ENOSYS;
      45    return -1;
      46  }
      47  
      48  #else /* HAVE_GRP_H */
      49  # include <grp.h>
      50  
      51  # define STREQ(a, b) (strcmp (a, b) == 0)
      52  
      53  /* Like 'getgroups', but for user USERNAME instead of for the current
      54     process.  Store at most MAXCOUNT group IDs in the GROUPLIST array.
      55     If GID is not -1, store it first (if possible).  GID should be the
      56     group ID (pw_gid) obtained from getpwuid, in case USERNAME is not
      57     listed in /etc/groups.  Upon failure, set errno and return -1.
      58     Otherwise, return the number of IDs we've written into GROUPLIST.  */
      59  
      60  int
      61  getugroups (int maxcount, gid_t *grouplist, char const *username,
      62              gid_t gid)
      63  {
      64    int count = 0;
      65  
      66    if (gid != (gid_t) -1)
      67      {
      68        if (maxcount != 0)
      69          grouplist[count] = gid;
      70        ++count;
      71      }
      72  
      73    setgrent ();
      74    while (1)
      75      {
      76        char **cp;
      77        struct group *grp;
      78  
      79        errno = 0;
      80        grp = getgrent ();
      81        if (grp == NULL)
      82          break;
      83  
      84        for (cp = grp->gr_mem; *cp; ++cp)
      85          {
      86            int n;
      87  
      88            if ( ! STREQ (username, *cp))
      89              continue;
      90  
      91            /* See if this group number is already on the list.  */
      92            for (n = 0; n < count; ++n)
      93              if (grouplist && grouplist[n] == grp->gr_gid)
      94                break;
      95  
      96            /* If it's a new group number, then try to add it to the list.  */
      97            if (n == count)
      98              {
      99                if (maxcount != 0)
     100                  {
     101                    if (count >= maxcount)
     102                      goto done;
     103                    grouplist[count] = grp->gr_gid;
     104                  }
     105                if (count == INT_MAX)
     106                  {
     107                    errno = EOVERFLOW;
     108                    goto done;
     109                  }
     110                count++;
     111              }
     112          }
     113      }
     114  
     115    if (errno != 0)
     116      count = -1;
     117  
     118   done:
     119    {
     120      int saved_errno = errno;
     121      endgrent ();
     122      errno = saved_errno;
     123    }
     124  
     125    return count;
     126  }
     127  
     128  #endif /* HAVE_GRP_H */