(root)/
glibc-2.38/
nss/
nss_files/
files-netgrp.c
       1  /* Netgroup file parser in nss_files modules.
       2     Copyright (C) 1996-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 <ctype.h>
      20  #include <errno.h>
      21  #include <netdb.h>
      22  #include <stdio.h>
      23  #include <stdio_ext.h>
      24  #include <stdlib.h>
      25  #include <string.h>
      26  #include "nsswitch.h"
      27  #include "netgroup.h"
      28  #include <nss_files.h>
      29  
      30  #define DATAFILE	"/etc/netgroup"
      31  
      32  libc_hidden_proto (_nss_files_endnetgrent)
      33  
      34  #define EXPAND(needed)							      \
      35    do									      \
      36      {									      \
      37        size_t old_cursor = result->cursor - result->data;		      \
      38        void *old_data = result->data;					      \
      39  									      \
      40        result->data_size += 512 > 2 * needed ? 512 : 2 * needed;		      \
      41        result->data = realloc (result->data, result->data_size);		      \
      42  									      \
      43        if (result->data == NULL)						      \
      44  	{								      \
      45  	  free (old_data);						      \
      46  	  status = NSS_STATUS_UNAVAIL;					      \
      47  	  goto the_end;							      \
      48  	}								      \
      49  									      \
      50        result->cursor = result->data + old_cursor;			      \
      51      }									      \
      52    while (0)
      53  
      54  
      55  enum nss_status
      56  _nss_files_setnetgrent (const char *group, struct __netgrent *result)
      57  {
      58    FILE *fp;
      59    enum nss_status status;
      60  
      61    if (group[0] == '\0')
      62      return NSS_STATUS_UNAVAIL;
      63  
      64    /* Find the netgroups file and open it.  */
      65    fp = __nss_files_fopen (DATAFILE);
      66    if (fp == NULL)
      67      status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
      68    else
      69      {
      70        /* Read the file line by line and try to find the description
      71  	 GROUP.  We must take care for long lines.  */
      72        char *line = NULL;
      73        size_t line_len = 0;
      74        const ssize_t group_len = strlen (group);
      75  
      76        status = NSS_STATUS_NOTFOUND;
      77        result->cursor = result->data;
      78  
      79        while (!__feof_unlocked (fp))
      80  	{
      81  	  ssize_t curlen = __getline (&line, &line_len, fp);
      82  	  int found;
      83  
      84  	  if (curlen < 0)
      85  	    {
      86  	      status = NSS_STATUS_NOTFOUND;
      87  	      break;
      88  	    }
      89  
      90  	  found = (curlen > group_len && strncmp (line, group, group_len) == 0
      91  		   && isspace (line[group_len]));
      92  
      93  	  /* Read the whole line (including continuation) and store it
      94  	     if FOUND in nonzero.  Otherwise we don't need it.  */
      95  	  if (found)
      96  	    {
      97  	      /* Store the data from the first line.  */
      98  	      EXPAND (curlen - group_len);
      99  	      memcpy (result->cursor, &line[group_len + 1],
     100  		      curlen - group_len);
     101  	      result->cursor += (curlen - group_len) - 1;
     102  	    }
     103  
     104  	  while (curlen > 1 && line[curlen - 1] == '\n'
     105  		 && line[curlen - 2] == '\\')
     106  	    {
     107  	      /* Yes, we have a continuation line.  */
     108  	      if (found)
     109  		/* Remove these characters from the stored line.  */
     110  		result->cursor -= 2;
     111  
     112  	      /* Get next line.  */
     113  	      curlen = __getline (&line, &line_len, fp);
     114  	      if (curlen <= 0)
     115  		break;
     116  
     117  	      if (found)
     118  		{
     119  		  /* Make sure we have enough room.  */
     120  		  EXPAND (1 + curlen + 1);
     121  
     122  		  /* Add separator in case next line starts immediately.  */
     123  		  *result->cursor++ = ' ';
     124  
     125  		  /* Copy new line.  */
     126  		  memcpy (result->cursor, line, curlen + 1);
     127  		  result->cursor += curlen;
     128  		}
     129  	    }
     130  
     131  	  if (found)
     132  	    {
     133  	      /* Now we have read the line.  */
     134  	      status = NSS_STATUS_SUCCESS;
     135  	      result->cursor = result->data;
     136  	      result->first = 1;
     137  	      break;
     138  	    }
     139  	}
     140  
     141      the_end:
     142        /* We don't need the file and the line buffer anymore.  */
     143        free (line);
     144        fclose (fp);
     145  
     146        if (status != NSS_STATUS_SUCCESS)
     147  	_nss_files_endnetgrent (result);
     148      }
     149  
     150    return status;
     151  }
     152  libc_hidden_def (_nss_files_setnetgrent)
     153  
     154  enum nss_status
     155  _nss_files_endnetgrent (struct __netgrent *result)
     156  {
     157    /* Free allocated memory for data if some is present.  */
     158    free (result->data);
     159    result->data = NULL;
     160    result->data_size = 0;
     161    result->cursor = NULL;
     162    return NSS_STATUS_SUCCESS;
     163  }
     164  libc_hidden_def (_nss_files_endnetgrent)
     165  
     166  static char *
     167  strip_whitespace (char *str)
     168  {
     169    char *cp = str;
     170  
     171    /* Skip leading spaces.  */
     172    while (isspace (*cp))
     173      cp++;
     174  
     175    str = cp;
     176    while (*cp != '\0' && ! isspace(*cp))
     177      cp++;
     178  
     179    /* Null-terminate, stripping off any trailing spaces.  */
     180    *cp = '\0';
     181  
     182    return *str == '\0' ? NULL : str;
     183  }
     184  
     185  enum nss_status
     186  _nss_netgroup_parseline (char **cursor, struct __netgrent *result,
     187  			 char *buffer, size_t buflen, int *errnop)
     188  {
     189    enum nss_status status;
     190    const char *host, *user, *domain;
     191    char *cp = *cursor;
     192  
     193    /* Some sanity checks.  */
     194    if (cp == NULL)
     195      return NSS_STATUS_NOTFOUND;
     196  
     197    /* First skip leading spaces.  */
     198    while (isspace (*cp))
     199      ++cp;
     200  
     201    if (*cp != '(')
     202      {
     203        /* We have a list of other netgroups.  */
     204        char *name = cp;
     205  
     206        while (*cp != '\0' && ! isspace (*cp))
     207  	++cp;
     208  
     209        if (name != cp)
     210  	{
     211  	  /* It is another netgroup name.  */
     212  	  int last = *cp == '\0';
     213  
     214  	  result->type = group_val;
     215  	  result->val.group = name;
     216  	  *cp = '\0';
     217  	  if (! last)
     218  	    ++cp;
     219  	  *cursor = cp;
     220  	  result->first = 0;
     221  
     222  	  return NSS_STATUS_SUCCESS;
     223  	}
     224  
     225        return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
     226      }
     227  
     228    /* Match host name.  */
     229    host = ++cp;
     230    while (*cp != ',')
     231      if (*cp++ == '\0')
     232        return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
     233  
     234    /* Match user name.  */
     235    user = ++cp;
     236    while (*cp != ',')
     237      if (*cp++ == '\0')
     238        return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
     239  
     240    /* Match domain name.  */
     241    domain = ++cp;
     242    while (*cp != ')')
     243      if (*cp++ == '\0')
     244        return result->first ? NSS_STATUS_NOTFOUND : NSS_STATUS_RETURN;
     245    ++cp;
     246  
     247  
     248    /* When we got here we have found an entry.  Before we can copy it
     249       to the private buffer we have to make sure it is big enough.  */
     250    if (cp - host > buflen)
     251      {
     252        *errnop = ERANGE;
     253        status = NSS_STATUS_TRYAGAIN;
     254      }
     255    else
     256      {
     257        memcpy (buffer, host, cp - host);
     258        result->type = triple_val;
     259  
     260        buffer[(user - host) - 1] = '\0';	/* Replace ',' with '\0'.  */
     261        result->val.triple.host = strip_whitespace (buffer);
     262  
     263        buffer[(domain - host) - 1] = '\0'; /* Replace ',' with '\0'.  */
     264        result->val.triple.user = strip_whitespace (buffer + (user - host));
     265  
     266        buffer[(cp - host) - 1] = '\0'; /* Replace ')' with '\0'.  */
     267        result->val.triple.domain = strip_whitespace (buffer + (domain - host));
     268  
     269        status = NSS_STATUS_SUCCESS;
     270  
     271        /* Remember where we stopped reading.  */
     272        *cursor = cp;
     273  
     274        result->first = 0;
     275      }
     276  
     277    return status;
     278  }
     279  libc_hidden_def (_nss_netgroup_parseline)
     280  
     281  
     282  enum nss_status
     283  _nss_files_getnetgrent_r (struct __netgrent *result, char *buffer,
     284  			  size_t buflen, int *errnop)
     285  {
     286    enum nss_status status;
     287  
     288    status = _nss_netgroup_parseline (&result->cursor, result, buffer, buflen,
     289  				    errnop);
     290  
     291    return status;
     292  }
     293  libc_hidden_def (_nss_files_getnetgrent_r)