Blame nss/nss_files/files-XXX.c

Packit 6c4009
/* Common code for file-based databases in nss_files module.
Packit 6c4009
   Copyright (C) 1996-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <fcntl.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
#include "nsswitch.h"
Packit Service 43bdf7
#include <nss_files.h>
Packit 6c4009
Packit 6c4009
#include <kernel-features.h>
Packit 6c4009
Packit 6c4009
/* These symbols are defined by the including source file:
Packit 6c4009
Packit 6c4009
   ENTNAME -- database name of the structure and functions (hostent, pwent).
Packit 6c4009
   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
Packit 6c4009
   DATABASE -- string of the database file's name ("hosts", "passwd").
Packit 6c4009
Packit 6c4009
   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
Packit 6c4009
Packit 6c4009
   Also see files-parse.c.
Packit 6c4009
*/
Packit 6c4009
Packit 6c4009
#define ENTNAME_r	CONCAT(ENTNAME,_r)
Packit 6c4009
Packit 6c4009
#define DATAFILE	"/etc/" DATABASE
Packit 6c4009
Packit 6c4009
#ifdef NEED_H_ERRNO
Packit 6c4009
# include <netdb.h>
Packit 6c4009
# define H_ERRNO_PROTO	, int *herrnop
Packit 6c4009
# define H_ERRNO_ARG	, herrnop
Packit 6c4009
# define H_ERRNO_SET(val) (*herrnop = (val))
Packit 6c4009
#else
Packit 6c4009
# define H_ERRNO_PROTO
Packit 6c4009
# define H_ERRNO_ARG
Packit 6c4009
# define H_ERRNO_SET(val) ((void) 0)
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#ifndef EXTRA_ARGS
Packit 6c4009
# define EXTRA_ARGS
Packit 6c4009
# define EXTRA_ARGS_DECL
Packit 6c4009
# define EXTRA_ARGS_VALUE
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
/* Locks the static variables in this file.  */
Packit 6c4009
__libc_lock_define_initialized (static, lock)
Packit 6c4009

Packit 6c4009
/* Maintenance of the stream open on the database file.  For getXXent
Packit 6c4009
   operations the stream needs to be held open across calls, the other
Packit 6c4009
   getXXbyYY operations all use their own stream.  */
Packit 6c4009
Packit 6c4009
static FILE *stream;
Packit 6c4009
Packit 6c4009
/* Open database file if not already opened.  */
Packit 6c4009
static enum nss_status
Packit 6c4009
internal_setent (FILE **stream)
Packit 6c4009
{
Packit 6c4009
  enum nss_status status = NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  if (*stream == NULL)
Packit 6c4009
    {
Packit Service 43bdf7
      *stream = __nss_files_fopen (DATAFILE);
Packit 6c4009
Packit 6c4009
      if (*stream == NULL)
Packit 6c4009
	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    rewind (*stream);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Thread-safe, exported version of that.  */
Packit 6c4009
enum nss_status
Packit 6c4009
CONCAT(_nss_files_set,ENTNAME) (int stayopen)
Packit 6c4009
{
Packit 6c4009
  enum nss_status status;
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
  status = internal_setent (&stream);
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Close the database file.  */
Packit 6c4009
static void
Packit 6c4009
internal_endent (FILE **stream)
Packit 6c4009
{
Packit 6c4009
  if (*stream != NULL)
Packit 6c4009
    {
Packit 6c4009
      fclose (*stream);
Packit 6c4009
      *stream = NULL;
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Thread-safe, exported version of that.  */
Packit 6c4009
enum nss_status
Packit 6c4009
CONCAT(_nss_files_end,ENTNAME) (void)
Packit 6c4009
{
Packit 6c4009
  __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
  internal_endent (&stream);
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
Packit 6c4009
/* Parsing the database file into `struct STRUCTURE' data structures.  */
Packit 6c4009
static enum nss_status
Packit 6c4009
internal_getent (FILE *stream, struct STRUCTURE *result,
Packit 6c4009
		 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
Packit 6c4009
		 EXTRA_ARGS_DECL)
Packit 6c4009
{
Packit Service 6de65a
  char *p;
Packit 6c4009
  struct parser_data *data = (void *) buffer;
Packit 6c4009
  size_t linebuflen = buffer + buflen - data->linebuffer;
Packit Service 6de65a
  int parse_result;
Packit 6c4009
Packit 6c4009
  if (buflen < sizeof *data + 2)
Packit 6c4009
    {
Packit 6c4009
      *errnop = ERANGE;
Packit 6c4009
      H_ERRNO_SET (NETDB_INTERNAL);
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  while (true)
Packit 6c4009
    {
Packit Service 6de65a
      ssize_t r = __libc_readline_unlocked
Packit Service 6de65a
	(stream, data->linebuffer, linebuflen);
Packit Service 6de65a
      if (r < 0)
Packit Service 6de65a
	{
Packit Service 6de65a
	  *errnop = errno;
Packit Service 6de65a
	  H_ERRNO_SET (NETDB_INTERNAL);
Packit Service 6de65a
	  if (*errnop == ERANGE)
Packit Service 6de65a
	    /* Request larger buffer.  */
Packit Service 6de65a
	    return NSS_STATUS_TRYAGAIN;
Packit Service 6de65a
	  else
Packit Service 6de65a
	    /* Other read failure.  */
Packit Service 6de65a
	    return NSS_STATUS_UNAVAIL;
Packit Service 6de65a
	}
Packit Service 6de65a
      else if (r == 0)
Packit 6c4009
	{
Packit 6c4009
	  /* End of file.  */
Packit 6c4009
	  H_ERRNO_SET (HOST_NOT_FOUND);
Packit 6c4009
	  return NSS_STATUS_NOTFOUND;
Packit 6c4009
	}
Packit Service 6de65a
Packit Service 6de65a
      /* Everything OK.  Now skip leading blanks.  */
Packit Service 6de65a
      p = data->linebuffer;
Packit Service 6de65a
      while (isspace (*p))
Packit Service 6de65a
	++p;
Packit Service 6de65a
Packit Service 6de65a
      /* Ignore empty and comment lines.  */
Packit Service 6de65a
      if (*p == '\0' || *p == '#')
Packit Service 6de65a
	continue;
Packit Service 6de65a
Packit Service 6de65a
      /* Parse the line.   */
Packit Service 6de65a
      *errnop = EINVAL;
Packit Service 6de65a
      parse_result = parse_line (p, result, data, buflen, errnop EXTRA_ARGS);
Packit Service 6de65a
Packit Service 6de65a
      if (parse_result == -1)
Packit 6c4009
	{
Packit Service 6de65a
	  if (*errnop == ERANGE)
Packit 6c4009
	    {
Packit Service 6de65a
	      /* Return to the original file position at the beginning
Packit Service 6de65a
		 of the line, so that the next call can read it again
Packit Service 6de65a
		 if necessary.  */
Packit Service 6de65a
	      if (__fseeko64 (stream, -r, SEEK_CUR) != 0)
Packit Service 6de65a
		{
Packit Service 6de65a
		  if (errno == ERANGE)
Packit Service 6de65a
		    *errnop = EINVAL;
Packit Service 6de65a
		  else
Packit Service 6de65a
		    *errnop = errno;
Packit Service 6de65a
		  H_ERRNO_SET (NETDB_INTERNAL);
Packit Service 6de65a
		  return NSS_STATUS_UNAVAIL;
Packit Service 6de65a
		}
Packit 6c4009
	    }
Packit Service 6de65a
	  H_ERRNO_SET (NETDB_INTERNAL);
Packit Service 6de65a
	  return NSS_STATUS_TRYAGAIN;
Packit 6c4009
	}
Packit 6c4009
Packit Service 6de65a
      /* Return the data if parsed successfully.  */
Packit Service 6de65a
      if (parse_result != 0)
Packit Service 6de65a
	return NSS_STATUS_SUCCESS;
Packit Service 6de65a
Packit Service 6de65a
      /* If it is invalid, loop to get the next line of the file to
Packit Service 6de65a
	 parse.  */
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Return the next entry from the database file, doing locking.  */
Packit 6c4009
enum nss_status
Packit 6c4009
CONCAT(_nss_files_get,ENTNAME_r) (struct STRUCTURE *result, char *buffer,
Packit 6c4009
				  size_t buflen, int *errnop H_ERRNO_PROTO)
Packit 6c4009
{
Packit 6c4009
  /* Return next entry in host file.  */
Packit 6c4009
  enum nss_status status = NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
  /* Be prepared that the set*ent function was not called before.  */
Packit 6c4009
  if (stream == NULL)
Packit 6c4009
    {
Packit 6c4009
      int save_errno = errno;
Packit 6c4009
Packit 6c4009
      status = internal_setent (&stream);
Packit 6c4009
Packit 6c4009
      __set_errno (save_errno);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    status = internal_getent (stream, result, buffer, buflen, errnop
Packit 6c4009
			      H_ERRNO_ARG EXTRA_ARGS_VALUE);
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
/* Macro for defining lookup functions for this file-based database.
Packit 6c4009
Packit 6c4009
   NAME is the name of the lookup; e.g. `hostbyname'.
Packit 6c4009
Packit 6c4009
   DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c
Packit 6c4009
   e.g. `1 + sizeof (id) * 4'.
Packit 6c4009
Packit 6c4009
   PROTO is the potentially empty list of other parameters.
Packit 6c4009
Packit 6c4009
   BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
Packit 6c4009
   to the lookup key arguments and does `break;' if they match.  */
Packit 6c4009
Packit 6c4009
#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
Packit 6c4009
enum nss_status								      \
Packit 6c4009
_nss_files_get##name##_r (proto,					      \
Packit 6c4009
			  struct STRUCTURE *result, char *buffer,	      \
Packit 6c4009
			  size_t buflen, int *errnop H_ERRNO_PROTO)	      \
Packit 6c4009
{									      \
Packit 6c4009
  enum nss_status status;						      \
Packit 6c4009
  FILE *stream = NULL;							      \
Packit 6c4009
									      \
Packit 6c4009
  /* Open file.  */							      \
Packit 6c4009
  status = internal_setent (&stream);					      \
Packit 6c4009
									      \
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)					      \
Packit 6c4009
    {									      \
Packit 6c4009
      while ((status = internal_getent (stream, result, buffer, buflen, errnop \
Packit 6c4009
					H_ERRNO_ARG EXTRA_ARGS_VALUE))	      \
Packit 6c4009
	     == NSS_STATUS_SUCCESS)					      \
Packit 6c4009
	{ break_if_match }						      \
Packit 6c4009
									      \
Packit 6c4009
      internal_endent (&stream);					      \
Packit 6c4009
    }									      \
Packit 6c4009
									      \
Packit 6c4009
  return status;							      \
Packit 6c4009
}