Blame files-XXX.c

Packit 231c70
/* Common code for file-based databases in nss_files module.
Packit 231c70
   Copyright (C) 1996-2013 Free Software Foundation, Inc.
Packit 231c70
   This file is part of the GNU C Library.
Packit 231c70
Packit 231c70
   The GNU C Library is free software; you can redistribute it and/or
Packit 231c70
   modify it under the terms of the GNU Lesser General Public
Packit 231c70
   License as published by the Free Software Foundation; either
Packit 231c70
   version 2.1 of the License, or (at your option) any later version.
Packit 231c70
Packit 231c70
   The GNU C Library is distributed in the hope that it will be useful,
Packit 231c70
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 231c70
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 231c70
   Lesser General Public License for more details.
Packit 231c70
Packit 231c70
   You should have received a copy of the GNU Lesser General Public
Packit 231c70
   License along with the GNU C Library; if not, see
Packit 231c70
   <http://www.gnu.org/licenses/>.  */
Packit 231c70
Packit 231c70
#include <nss.h>
Packit 231c70
#include <stdio.h>
Packit 231c70
#include <ctype.h>
Packit 231c70
#include <errno.h>
Packit 231c70
#include <fcntl.h>
Packit 231c70
#include "compat.h"
Packit 231c70
Packit 231c70
/* These symbols are defined by the including source file:
Packit 231c70
Packit 231c70
   ENTNAME -- database name of the structure and functions (hostent, pwent).
Packit 231c70
   STRUCTURE -- struct name, define only if not ENTNAME (passwd, group).
Packit 231c70
   DATABASE -- string of the database file's name ("hosts", "passwd").
Packit 231c70
Packit 231c70
   NEED_H_ERRNO - defined iff an arg `int *herrnop' is used.
Packit 231c70
Packit 231c70
   Also see files-parse.c.
Packit 231c70
*/
Packit 231c70
Packit 231c70
#define ENTNAME_r	CONCAT(ENTNAME,_r)
Packit 231c70
Packit 231c70
#define DATAFILE	ALTFILES_DATADIR "/" DATABASE
Packit 231c70
Packit 231c70
#ifdef NEED_H_ERRNO
Packit 231c70
# include <netdb.h>
Packit 231c70
# define H_ERRNO_PROTO	, int *herrnop
Packit 231c70
# define H_ERRNO_ARG	, herrnop
Packit 231c70
# define H_ERRNO_SET(val) (*herrnop = (val))
Packit 231c70
#else
Packit 231c70
# define H_ERRNO_PROTO
Packit 231c70
# define H_ERRNO_ARG
Packit 231c70
# define H_ERRNO_SET(val) ((void) 0)
Packit 231c70
#endif
Packit 231c70
Packit 231c70
#ifndef EXTRA_ARGS
Packit 231c70
# define EXTRA_ARGS
Packit 231c70
# define EXTRA_ARGS_DECL
Packit 231c70
# define EXTRA_ARGS_VALUE
Packit 231c70
#endif
Packit 231c70
Packit 231c70
/* Locks the static variables in this file.  */
Packit 231c70
__libc_lock_define_initialized (static, lock)
Packit 231c70

Packit 231c70
/* Maintenance of the shared stream open on the database file.  */
Packit 231c70
Packit 231c70
static FILE *stream;
Packit 231c70
static fpos_t position;
Packit 231c70
static enum { nouse, getent, getby } last_use;
Packit 231c70
static int keep_stream;
Packit 231c70
Packit 231c70
/* Open database file if not already opened.  */
Packit 231c70
static enum nss_status
Packit 231c70
internal_setent (int stayopen)
Packit 231c70
{
Packit 231c70
  enum nss_status status = NSS_STATUS_SUCCESS;
Packit 231c70
Packit 231c70
  if (stream == NULL)
Packit 231c70
    {
Packit 231c70
      stream = fopen (DATAFILE, "rce");
Packit 231c70
Packit 231c70
      if (stream == NULL)
Packit 231c70
	status = errno == EAGAIN ? NSS_STATUS_TRYAGAIN : NSS_STATUS_UNAVAIL;
Packit 231c70
      else
Packit 231c70
	{
Packit 231c70
#if !defined O_CLOEXEC || !defined __ASSUME_O_CLOEXEC
Packit 231c70
# ifdef O_CLOEXEC
Packit 231c70
	  if (__have_o_cloexec <= 0)
Packit 231c70
# endif
Packit 231c70
	    {
Packit 231c70
	      /* We have to make sure the file is  `closed on exec'.  */
Packit 231c70
	      int result;
Packit 231c70
	      int flags;
Packit 231c70
Packit 231c70
	      result = flags = fcntl (fileno (stream), F_GETFD, 0);
Packit 231c70
	      if (result >= 0)
Packit 231c70
		{
Packit 231c70
# ifdef O_CLOEXEC
Packit 231c70
		  if (__have_o_cloexec == 0)
Packit 231c70
		    __have_o_cloexec = (flags & FD_CLOEXEC) == 0 ? -1 : 1;
Packit 231c70
		  if (__have_o_cloexec < 0)
Packit 231c70
# endif
Packit 231c70
		    {
Packit 231c70
		      flags |= FD_CLOEXEC;
Packit 231c70
		      result = fcntl (fileno (stream), F_SETFD, flags);
Packit 231c70
		    }
Packit 231c70
		}
Packit 231c70
	      if (result < 0)
Packit 231c70
		{
Packit 231c70
		  /* Something went wrong.  Close the stream and return a
Packit 231c70
		     failure.  */
Packit 231c70
		  fclose (stream);
Packit 231c70
		  stream = NULL;
Packit 231c70
		  status = NSS_STATUS_UNAVAIL;
Packit 231c70
		}
Packit 231c70
	    }
Packit 231c70
#endif
Packit 231c70
	}
Packit 231c70
    }
Packit 231c70
  else
Packit 231c70
    rewind (stream);
Packit 231c70
Packit 231c70
  /* Remember STAYOPEN flag.  */
Packit 231c70
  if (stream != NULL)
Packit 231c70
    keep_stream |= stayopen;
Packit 231c70
Packit 231c70
  return status;
Packit 231c70
}
Packit 231c70
Packit 231c70
Packit 231c70
/* Thread-safe, exported version of that.  */
Packit 231c70
enum nss_status
Packit 231c70
CONCAT(CONCAT(CONCAT(_nss_, ALTFILES_MODULE_NAME), _set), ENTNAME) (int stayopen)
Packit 231c70
{
Packit 231c70
  enum nss_status status;
Packit 231c70
Packit 231c70
  __libc_lock_lock (lock);
Packit 231c70
Packit 231c70
  status = internal_setent (stayopen);
Packit 231c70
Packit 231c70
  if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
Packit 231c70
    {
Packit 231c70
      fclose (stream);
Packit 231c70
      stream = NULL;
Packit 231c70
      status = NSS_STATUS_UNAVAIL;
Packit 231c70
    }
Packit 231c70
Packit 231c70
  last_use = getent;
Packit 231c70
Packit 231c70
  __libc_lock_unlock (lock);
Packit 231c70
Packit 231c70
  return status;
Packit 231c70
}
Packit 231c70
Packit 231c70
Packit 231c70
/* Close the database file.  */
Packit 231c70
static void
Packit 231c70
internal_endent (void)
Packit 231c70
{
Packit 231c70
  if (stream != NULL)
Packit 231c70
    {
Packit 231c70
      fclose (stream);
Packit 231c70
      stream = NULL;
Packit 231c70
    }
Packit 231c70
}
Packit 231c70
Packit 231c70
Packit 231c70
/* Thread-safe, exported version of that.  */
Packit 231c70
enum nss_status
Packit 231c70
CONCAT(CONCAT(CONCAT(_nss_, ALTFILES_MODULE_NAME), _end), ENTNAME) (void)
Packit 231c70
{
Packit 231c70
  __libc_lock_lock (lock);
Packit 231c70
Packit 231c70
  internal_endent ();
Packit 231c70
Packit 231c70
  /* Reset STAYOPEN flag.  */
Packit 231c70
  keep_stream = 0;
Packit 231c70
Packit 231c70
  __libc_lock_unlock (lock);
Packit 231c70
Packit 231c70
  return NSS_STATUS_SUCCESS;
Packit 231c70
}
Packit 231c70

Packit 231c70
/* Parsing the database file into `struct STRUCTURE' data structures.  */
Packit 231c70
Packit 231c70
static enum nss_status
Packit 231c70
internal_getent (struct STRUCTURE *result,
Packit 231c70
		 char *buffer, size_t buflen, int *errnop H_ERRNO_PROTO
Packit 231c70
		 EXTRA_ARGS_DECL)
Packit 231c70
{
Packit 231c70
  char *p;
Packit 231c70
  struct parser_data *data = (void *) buffer;
Packit 231c70
  int linebuflen = buffer + buflen - data->linebuffer;
Packit 231c70
  int parse_result;
Packit 231c70
Packit 231c70
  if (buflen < sizeof *data + 2)
Packit 231c70
    {
Packit 231c70
      *errnop = ERANGE;
Packit 231c70
      H_ERRNO_SET (NETDB_INTERNAL);
Packit 231c70
      return NSS_STATUS_TRYAGAIN;
Packit 231c70
    }
Packit 231c70
Packit 231c70
  do
Packit 231c70
    {
Packit 231c70
      /* Terminate the line so that we can test for overflow.  */
Packit 231c70
      ((unsigned char *) data->linebuffer)[linebuflen - 1] = '\xff';
Packit 231c70
Packit 231c70
      p = fgets_unlocked (data->linebuffer, linebuflen, stream);
Packit 231c70
      if (p == NULL)
Packit 231c70
	{
Packit 231c70
	  /* End of file or read error.  */
Packit 231c70
	  H_ERRNO_SET (HOST_NOT_FOUND);
Packit 231c70
	  return NSS_STATUS_NOTFOUND;
Packit 231c70
	}
Packit 231c70
      else if (((unsigned char *) data->linebuffer)[linebuflen - 1] != 0xff)
Packit 231c70
	{
Packit 231c70
	  /* The line is too long.  Give the user the opportunity to
Packit 231c70
	     enlarge the buffer.  */
Packit 231c70
	  *errnop = ERANGE;
Packit 231c70
	  H_ERRNO_SET (NETDB_INTERNAL);
Packit 231c70
	  return NSS_STATUS_TRYAGAIN;
Packit 231c70
	}
Packit 231c70
Packit 231c70
      /* Skip leading blanks.  */
Packit 231c70
      while (isspace (*p))
Packit 231c70
	++p;
Packit 231c70
    }
Packit 231c70
  while (*p == '\0' || *p == '#' /* Ignore empty and comment lines.  */
Packit 231c70
	 /* Parse the line.  If it is invalid, loop to get the next
Packit 231c70
	    line of the file to parse.  */
Packit 231c70
	 || ! (parse_result = parse_line (p, result, data, buflen, errnop
Packit 231c70
					  EXTRA_ARGS)));
Packit 231c70
Packit 231c70
  if (__builtin_expect (parse_result == -1, 0))
Packit 231c70
    {
Packit 231c70
      H_ERRNO_SET (NETDB_INTERNAL);
Packit 231c70
      return NSS_STATUS_TRYAGAIN;
Packit 231c70
    }
Packit 231c70
Packit 231c70
  /* Filled in RESULT with the next entry from the database file.  */
Packit 231c70
  return NSS_STATUS_SUCCESS;
Packit 231c70
}
Packit 231c70
Packit 231c70
Packit 231c70
/* Return the next entry from the database file, doing locking.  */
Packit 231c70
enum nss_status
Packit 231c70
CONCAT(CONCAT(CONCAT(_nss_, ALTFILES_MODULE_NAME), _get), ENTNAME_r) (struct STRUCTURE *result, char *buffer,
Packit 231c70
				  size_t buflen, int *errnop H_ERRNO_PROTO)
Packit 231c70
{
Packit 231c70
  /* Return next entry in host file.  */
Packit 231c70
  enum nss_status status = NSS_STATUS_SUCCESS;
Packit 231c70
Packit 231c70
  __libc_lock_lock (lock);
Packit 231c70
Packit 231c70
  /* Be prepared that the set*ent function was not called before.  */
Packit 231c70
  if (stream == NULL)
Packit 231c70
    {
Packit 231c70
      int save_errno = errno;
Packit 231c70
Packit 231c70
      status = internal_setent (0);
Packit 231c70
Packit 231c70
      __set_errno (save_errno);
Packit 231c70
Packit 231c70
      if (status == NSS_STATUS_SUCCESS && fgetpos (stream, &position) < 0)
Packit 231c70
	{
Packit 231c70
	  fclose (stream);
Packit 231c70
	  stream = NULL;
Packit 231c70
	  status = NSS_STATUS_UNAVAIL;
Packit 231c70
	}
Packit 231c70
    }
Packit 231c70
Packit 231c70
  if (status == NSS_STATUS_SUCCESS)
Packit 231c70
    {
Packit 231c70
      /* If the last use was not by the getent function we need the
Packit 231c70
	 position the stream.  */
Packit 231c70
      if (last_use != getent)
Packit 231c70
	{
Packit 231c70
	  if (fsetpos (stream, &position) < 0)
Packit 231c70
	    status = NSS_STATUS_UNAVAIL;
Packit 231c70
	  else
Packit 231c70
	    last_use = getent;
Packit 231c70
	}
Packit 231c70
Packit 231c70
      if (status == NSS_STATUS_SUCCESS)
Packit 231c70
	{
Packit 231c70
	  status = internal_getent (result, buffer, buflen, errnop
Packit 231c70
				    H_ERRNO_ARG EXTRA_ARGS_VALUE);
Packit 231c70
Packit 231c70
	  /* Remember this position if we were successful.  If the
Packit 231c70
	     operation failed we give the user a chance to repeat the
Packit 231c70
	     operation (perhaps the buffer was too small).  */
Packit 231c70
	  if (status == NSS_STATUS_SUCCESS)
Packit 231c70
	    fgetpos (stream, &position);
Packit 231c70
	  else
Packit 231c70
	    /* We must make sure we reposition the stream the next call.  */
Packit 231c70
	    last_use = nouse;
Packit 231c70
	}
Packit 231c70
    }
Packit 231c70
Packit 231c70
  __libc_lock_unlock (lock);
Packit 231c70
Packit 231c70
  return status;
Packit 231c70
}
Packit 231c70

Packit 231c70
/* Macro for defining lookup functions for this file-based database.
Packit 231c70
Packit 231c70
   NAME is the name of the lookup; e.g. `hostbyname'.
Packit 231c70
Packit 231c70
   DB_CHAR, KEYPATTERN, KEYSIZE are ignored here but used by db-XXX.c
Packit 231c70
   e.g. `1 + sizeof (id) * 4'.
Packit 231c70
Packit 231c70
   PROTO is the potentially empty list of other parameters.
Packit 231c70
Packit 231c70
   BREAK_IF_MATCH is a block of code which compares `struct STRUCTURE *result'
Packit 231c70
   to the lookup key arguments and does `break;' if they match.  */
Packit 231c70
Packit 231c70
#define DB_LOOKUP(name, db_char, keysize, keypattern, break_if_match, proto...)\
Packit 231c70
enum nss_status								      \
Packit 231c70
CONCAT(CONCAT(_nss_, ALTFILES_MODULE_NAME), _get ## name ## _r) (proto,	      \
Packit 231c70
			  struct STRUCTURE *result, char *buffer,	      \
Packit 231c70
			  size_t buflen, int *errnop H_ERRNO_PROTO)	      \
Packit 231c70
{									      \
Packit 231c70
  enum nss_status status;						      \
Packit 231c70
									      \
Packit 231c70
  __libc_lock_lock (lock);						      \
Packit 231c70
									      \
Packit 231c70
  /* Reset file pointer to beginning or open file.  */			      \
Packit 231c70
  status = internal_setent (keep_stream);				      \
Packit 231c70
									      \
Packit 231c70
  if (status == NSS_STATUS_SUCCESS)					      \
Packit 231c70
    {									      \
Packit 231c70
      /* Tell getent function that we have repositioned the file pointer.  */ \
Packit 231c70
      last_use = getby;							      \
Packit 231c70
									      \
Packit 231c70
      while ((status = internal_getent (result, buffer, buflen, errnop	      \
Packit 231c70
					H_ERRNO_ARG EXTRA_ARGS_VALUE))	      \
Packit 231c70
	     == NSS_STATUS_SUCCESS)					      \
Packit 231c70
	{ break_if_match }						      \
Packit 231c70
									      \
Packit 231c70
      if (! keep_stream)						      \
Packit 231c70
	internal_endent ();						      \
Packit 231c70
    }									      \
Packit 231c70
									      \
Packit 231c70
  __libc_lock_unlock (lock);						      \
Packit 231c70
									      \
Packit 231c70
  return status;							      \
Packit 231c70
}