(root)/
glibc-2.38/
hesiod/
nss_hesiod/
hesiod-grp.c
       1  /* Copyright (C) 1997-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <ctype.h>
      19  #include <errno.h>
      20  #include <grp.h>
      21  #include <hesiod.h>
      22  #include <nss.h>
      23  #include <stdio.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include <sys/param.h>
      27  
      28  NSS_DECLARE_MODULE_FUNCTIONS (hesiod)
      29  
      30  /* Get the declaration of the parser function.  */
      31  #define ENTNAME grent
      32  #define STRUCTURE group
      33  #define EXTERN_PARSER
      34  #include <nss/nss_files/files-parse.c>
      35  
      36  enum nss_status
      37  _nss_hesiod_setgrent (int stayopen)
      38  {
      39    return NSS_STATUS_SUCCESS;
      40  }
      41  
      42  enum nss_status
      43  _nss_hesiod_endgrent (void)
      44  {
      45    return NSS_STATUS_SUCCESS;
      46  }
      47  
      48  static enum nss_status
      49  lookup (const char *name, const char *type, struct group *grp,
      50  	char *buffer, size_t buflen, int *errnop)
      51  {
      52    struct parser_data *data = (void *) buffer;
      53    size_t linebuflen;
      54    void *context;
      55    char **list;
      56    int parse_res;
      57    size_t len;
      58    int olderr = errno;
      59  
      60    if (hesiod_init (&context) < 0)
      61      return NSS_STATUS_UNAVAIL;
      62  
      63    list = hesiod_resolve (context, name, type);
      64    if (list == NULL)
      65      {
      66        int err = errno;
      67        hesiod_end (context);
      68        __set_errno (olderr);
      69        return err == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
      70      }
      71  
      72    linebuflen = buffer + buflen - data->linebuffer;
      73    len = strlen (*list) + 1;
      74    if (linebuflen < len)
      75      {
      76        hesiod_free_list (context, list);
      77        hesiod_end (context);
      78        *errnop = ERANGE;
      79        return NSS_STATUS_TRYAGAIN;
      80      }
      81  
      82    memcpy (data->linebuffer, *list, len);
      83    hesiod_free_list (context, list);
      84    hesiod_end (context);
      85  
      86    parse_res = _nss_files_parse_grent (buffer, grp, data, buflen, errnop);
      87    if (parse_res < 1)
      88      {
      89        __set_errno (olderr);
      90        return parse_res == -1 ? NSS_STATUS_TRYAGAIN : NSS_STATUS_NOTFOUND;
      91      }
      92  
      93    return NSS_STATUS_SUCCESS;
      94  }
      95  
      96  enum nss_status
      97  _nss_hesiod_getgrnam_r (const char *name, struct group *grp,
      98  			char *buffer, size_t buflen, int *errnop)
      99  {
     100    return lookup (name, "group", grp, buffer, buflen, errnop);
     101  }
     102  
     103  enum nss_status
     104  _nss_hesiod_getgrgid_r (gid_t gid, struct group *grp,
     105  			char *buffer, size_t buflen, int *errnop)
     106  {
     107    char gidstr[21];	/* We will probably never have a gid_t with more
     108  			   than 64 bits.  */
     109  
     110    snprintf (gidstr, sizeof gidstr, "%d", gid);
     111  
     112    return lookup (gidstr, "gid", grp, buffer, buflen, errnop);
     113  }
     114  
     115  static int
     116  internal_gid_in_list (const gid_t *list, const gid_t g, long int len)
     117  {
     118    while (len > 0)
     119      {
     120        if (*list == g)
     121  	return 1;
     122        --len;
     123        ++list;
     124      }
     125    return 0;
     126  }
     127  
     128  static enum nss_status
     129  internal_gid_from_group (void *context, const char *groupname, gid_t *group)
     130  {
     131    char **grp_res;
     132    enum nss_status status = NSS_STATUS_NOTFOUND;
     133  
     134    grp_res = hesiod_resolve (context, groupname, "group");
     135    if (grp_res != NULL && *grp_res != NULL)
     136      {
     137        char *p = *grp_res;
     138  
     139        /* Skip to third field.  */
     140        while (*p != '\0' && *p != ':')
     141  	++p;
     142        if (*p != '\0')
     143  	++p;
     144        while (*p != '\0' && *p != ':')
     145  	++p;
     146        if (*p != '\0')
     147  	{
     148  	  char *endp;
     149  	  char *q = ++p;
     150  	  long int val;
     151  
     152  	  while (*q != '\0' && *q != ':')
     153  	    ++q;
     154  
     155  	  val = strtol (p, &endp, 10);
     156  	  if (sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
     157  	    {
     158  	      *group = val;
     159  	      if (endp == q && endp != p)
     160  		status = NSS_STATUS_SUCCESS;
     161  	    }
     162          }
     163        hesiod_free_list (context, grp_res);
     164      }
     165    return status;
     166  }
     167  
     168  enum nss_status
     169  _nss_hesiod_initgroups_dyn (const char *user, gid_t group, long int *start,
     170  			    long int *size, gid_t **groupsp, long int limit,
     171  			    int *errnop)
     172  {
     173    enum nss_status status = NSS_STATUS_SUCCESS;
     174    char **list = NULL;
     175    char *p;
     176    void *context;
     177    gid_t *groups = *groupsp;
     178    int save_errno;
     179  
     180    if (hesiod_init (&context) < 0)
     181      return NSS_STATUS_UNAVAIL;
     182  
     183    list = hesiod_resolve (context, user, "grplist");
     184  
     185    if (list == NULL)
     186      {
     187        hesiod_end (context);
     188        return errno == ENOENT ? NSS_STATUS_NOTFOUND : NSS_STATUS_UNAVAIL;
     189      }
     190  
     191    save_errno = errno;
     192  
     193    p = *list;
     194    while (*p != '\0')
     195      {
     196        char *endp;
     197        char *q;
     198        long int val;
     199  
     200        status = NSS_STATUS_NOTFOUND;
     201  
     202        q = p;
     203        while (*q != '\0' && *q != ':' && *q != ',')
     204  	++q;
     205  
     206        if (*q != '\0')
     207  	*q++ = '\0';
     208  
     209        __set_errno (0);
     210        val = strtol (p, &endp, 10);
     211        /* Test whether the number is representable in a variable of
     212           type `gid_t'.  If not ignore the number.  */
     213        if ((sizeof (gid_t) == sizeof (long int) || (gid_t) val == val)
     214  	  && errno == 0)
     215  	{
     216  	  if (*endp == '\0' && endp != p)
     217  	    {
     218  	      group = val;
     219  	      status = NSS_STATUS_SUCCESS;
     220  	    }
     221  	  else
     222  	    status = internal_gid_from_group (context, p, &group);
     223  
     224  	  if (status == NSS_STATUS_SUCCESS
     225  	      && !internal_gid_in_list (groups, group, *start))
     226  	    {
     227  	      if (__glibc_unlikely (*start == *size))
     228  		{
     229  		  /* Need a bigger buffer.  */
     230  		  gid_t *newgroups;
     231  		  long int newsize;
     232  
     233  		  if (limit > 0 && *size == limit)
     234  		    /* We reached the maximum.  */
     235  		    goto done;
     236  
     237  		  if (limit <= 0)
     238  		    newsize = 2 * *size;
     239  		  else
     240  		    newsize = MIN (limit, 2 * *size);
     241  
     242  		  newgroups = realloc (groups, newsize * sizeof (*groups));
     243  		  if (newgroups == NULL)
     244  		    goto done;
     245  		  *groupsp = groups = newgroups;
     246  		  *size = newsize;
     247  		}
     248  
     249  	      groups[(*start)++] = group;
     250  	    }
     251  	}
     252  
     253        p = q;
     254      }
     255  
     256    __set_errno (save_errno);
     257  
     258   done:
     259    hesiod_free_list (context, list);
     260    hesiod_end (context);
     261  
     262    return NSS_STATUS_SUCCESS;
     263  }