(root)/
glibc-2.38/
nss/
nss_files/
files-XXX.c
       1  /* Common code for file-based databases in nss_files module.
       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 <stdio.h>
      20  #include <ctype.h>
      21  #include <errno.h>
      22  #include <fcntl.h>
      23  #include <libc-lock.h>
      24  #include "nsswitch.h"
      25  #include <nss_files.h>
      26  
      27  #include <kernel-features.h>
      28  
      29  /* These symbols are defined by the including source file:
      30  
      31     ENTNAME -- database name of the structure and functions (hostent, pwent).
      32     STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
      33     DATABASE -- string of the database file's name ("hosts", "passwd").
      34  
      35     NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
      36  
      37     Also see files-parse.c.
      38  */
      39  
      40  #define ENTNAME_r	CONCAT(ENTNAME,_r)
      41  
      42  #define DATAFILE	"/etc/" DATABASE
      43  
      44  #ifdef NEED_H_ERRNO
      45  # include <netdb.h>
      46  # define H_ERRNO_PROTO	, int *herrnop
      47  # define H_ERRNO_ARG	, herrnop
      48  # define H_ERRNO_ARG_OR_NULL herrnop
      49  # define H_ERRNO_SET(val) (*herrnop = (val))
      50  #else
      51  # define H_ERRNO_PROTO
      52  # define H_ERRNO_ARG
      53  # define H_ERRNO_ARG_OR_NULL NULL
      54  # define H_ERRNO_SET(val) ((void) 0)
      55  #endif
      56  
      57  #ifndef EXTRA_ARGS
      58  # define EXTRA_ARGS
      59  # define EXTRA_ARGS_DECL
      60  # define EXTRA_ARGS_VALUE
      61  #endif
      62  
      63  
      64  /* Maintenance of the stream open on the database file.  For getXXent
      65     operations the stream needs to be held open across calls, the other
      66     getXXbyYY operations all use their own stream.  */
      67  
      68  /* Open database file if not already opened.  */
      69  static enum nss_status
      70  internal_setent (FILE **stream)
      71  {
      72    enum nss_status status = NSS_STATUS_SUCCESS;
      73  
      74    if (*stream == NULL)
      75      {
      76        *stream = __nss_files_fopen (DATAFILE);
      77  
      78        if (*stream == NULL)
      79  	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
      80      }
      81    else
      82      rewind (*stream);
      83  
      84    return status;
      85  }
      86  
      87  
      88  /* Thread-safe, exported version of that.  */
      89  enum nss_status
      90  CONCAT(_nss_files_set,ENTNAME) (int stayopen)
      91  {
      92    return __nss_files_data_setent (CONCAT (nss_file_, ENTNAME), DATAFILE);
      93  }
      94  libc_hidden_def (CONCAT (_nss_files_set,ENTNAME))
      95  
      96  enum nss_status
      97  CONCAT(_nss_files_end,ENTNAME) (void)
      98  {
      99    return __nss_files_data_endent (CONCAT (nss_file_, ENTNAME));
     100  }
     101  libc_hidden_def (CONCAT (_nss_files_end,ENTNAME))
     102  
     103  
     104  /* Parsing the database file into `struct STRUCTURE' data structures.  */
     105  static enum nss_status
     106  internal_getent (FILE *stream, struct STRUCTURE *result,
     107  		 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
     108  		 EXTRA_ARGS_DECL)
     109  {
     110    struct parser_data *data = (void *) buffer;
     111    size_t linebuflen = buffer + buflen - data->linebuffer;
     112    int saved_errno = errno;	/* Do not clobber errno on success.  */
     113  
     114    if (buflen < sizeof *data + 2)
     115      {
     116        *errnop = ERANGE;
     117        H_ERRNO_SET (NETDB_INTERNAL);
     118        return NSS_STATUS_TRYAGAIN;
     119      }
     120  
     121    while (true)
     122      {
     123        off64_t original_offset;
     124        int ret = __nss_readline (stream, data->linebuffer, linebuflen,
     125  				&original_offset);
     126        if (ret == ENOENT)
     127  	{
     128  	  /* End of file.  */
     129  	  H_ERRNO_SET (HOST_NOT_FOUND);
     130  	  __set_errno (saved_errno);
     131  	  return NSS_STATUS_NOTFOUND;
     132  	}
     133        else if (ret == 0)
     134  	{
     135  	  ret = __nss_parse_line_result (stream, original_offset,
     136  					 parse_line (data->linebuffer,
     137  						     result, data, buflen,
     138  						     errnop EXTRA_ARGS));
     139  	  if (ret == 0)
     140  	    {
     141  	      /* Line has been parsed successfully.  */
     142  	      __set_errno (saved_errno);
     143  	      return NSS_STATUS_SUCCESS;
     144  	    }
     145  	  else if (ret == EINVAL)
     146  	    /* If it is invalid, loop to get the next line of the file
     147  	       to parse.  */
     148  	    continue;
     149  	}
     150  
     151        *errnop = ret;
     152        H_ERRNO_SET (NETDB_INTERNAL);
     153        if (ret == ERANGE)
     154  	/* Request larger buffer.  */
     155  	return NSS_STATUS_TRYAGAIN;
     156        else
     157  	/* Other read failure.  */
     158  	return NSS_STATUS_UNAVAIL;
     159      }
     160  }
     161  
     162  
     163  /* Return the next entry from the database file, doing locking.  */
     164  enum nss_status
     165  CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
     166  				  size_t buflen, int *errnop H_ERRNO_PROTO)
     167  {
     168    /* Return next entry in host file.  */
     169  
     170    struct nss_files_per_file_data *data;
     171    enum nss_status status = __nss_files_data_open (&data,
     172  						  CONCAT (nss_file_, ENTNAME),
     173  						  DATAFILE,
     174  						  errnop, H_ERRNO_ARG_OR_NULL);
     175    if (status != NSS_STATUS_SUCCESS)
     176      return status;
     177  
     178    status = internal_getent (data->stream, result, buffer, buflen, errnop
     179  			    H_ERRNO_ARG EXTRA_ARGS_VALUE);
     180  
     181    __nss_files_data_put (data);
     182    return status;
     183  }
     184  libc_hidden_def (CONCAT (_nss_files_get,ENTNAME_r))
     185  
     186  /* Macro for defining lookup functions for this file-based database.
     187  
     188     NAME is the name of the lookup; e.g. `hostbyname'.
     189  
     190     DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c
     191     e.g. `1 + sizeof (id) * 4'.
     192  
     193     PROTO is the potentially empty list of other parameters.
     194  
     195     BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
     196     to the lookup key arguments and does `break;' if they match.  */
     197  
     198  #define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
     199  enum nss_status								      \
     200  _nss_files_get##name##_r (proto,					      \
     201  			  struct STRUCTURE *result, char *buffer,	      \
     202  			  size_t buflen, int *errnop H_ERRNO_PROTO)	      \
     203  {									      \
     204    enum nss_status status;						      \
     205    FILE *stream = NULL;							      \
     206  									      \
     207    /* Open file.  */							      \
     208    status = internal_setent (&stream);					      \
     209  									      \
     210    if (status == NSS_STATUS_SUCCESS)					      \
     211      {									      \
     212        while ((status = internal_getent (stream, result, buffer, buflen, errnop \
     213  					H_ERRNO_ARG EXTRA_ARGS_VALUE))	      \
     214  	     == NSS_STATUS_SUCCESS)					      \
     215  	{ break_if_match }						      \
     216  									      \
     217        fclose (stream);							      \
     218      }									      \
     219  									      \
     220    return status;							      \
     221  }									      \
     222  libc_hidden_def (_nss_files_get##name##_r)