Blame nss/nss_files/files-alias.c

Packit 6c4009
/* Mail alias file parser 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
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996.
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 <aliases.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 <stdlib.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
#include <kernel-features.h>
Packit 6c4009
Packit 6c4009
#include "nsswitch.h"
Packit Service 14e5e5
#include <nss_files.h>
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
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 14e5e5
      *stream = __nss_files_fopen ("/etc/aliases");
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
_nss_files_setaliasent (void)
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
_nss_files_endaliasent (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
/* Parsing the database file into `struct aliasent' data structures.  */
Packit 6c4009
static enum nss_status
Packit 6c4009
get_next_alias (FILE *stream, const char *match, struct aliasent *result,
Packit 6c4009
		char *buffer, size_t buflen, int *errnop)
Packit 6c4009
{
Packit 6c4009
  enum nss_status status = NSS_STATUS_NOTFOUND;
Packit 6c4009
  int ignore = 0;
Packit 6c4009
Packit 6c4009
  result->alias_members_len = 0;
Packit 6c4009
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* Now we are ready to process the input.  We have to read a
Packit 6c4009
	 line and all its continuations and construct the array of
Packit 6c4009
	 string pointers.  This pointers and the names itself have to
Packit 6c4009
	 be placed in BUFFER.  */
Packit 6c4009
      char *first_unused = buffer;
Packit 6c4009
      size_t room_left = buflen - (buflen % __alignof__ (char *));
Packit 6c4009
      char *line;
Packit 6c4009
Packit 6c4009
      /* Check whether the buffer is large enough for even trying to
Packit 6c4009
	 read something.  */
Packit 6c4009
      if (room_left < 2)
Packit 6c4009
	goto no_more_room;
Packit 6c4009
Packit 6c4009
      /* Read the first line.  It must contain the alias name and
Packit 6c4009
	 possibly some alias names.  */
Packit 6c4009
      first_unused[room_left - 1] = '\xff';
Packit 6c4009
      line = fgets_unlocked (first_unused, room_left, stream);
Packit 6c4009
      if (line == NULL)
Packit 6c4009
	/* Nothing to read.  */
Packit 6c4009
	break;
Packit 6c4009
      else if (first_unused[room_left - 1] != '\xff')
Packit 6c4009
	{
Packit 6c4009
	  /* The line is too long for our buffer.  */
Packit 6c4009
	no_more_room:
Packit 6c4009
	  *errnop = ERANGE;
Packit 6c4009
	  status = NSS_STATUS_TRYAGAIN;
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  char *cp;
Packit 6c4009
Packit 6c4009
	  /* If we are in IGNORE mode and the first character in the
Packit 6c4009
	     line is a white space we ignore the line and start
Packit 6c4009
	     reading the next.  */
Packit 6c4009
	  if (ignore && isspace (*first_unused))
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  /* Terminate the line for any case.  */
Packit 6c4009
	  cp = strpbrk (first_unused, "#\n");
Packit 6c4009
	  if (cp != NULL)
Packit 6c4009
	    *cp = '\0';
Packit 6c4009
Packit 6c4009
	  /* Skip leading blanks.  */
Packit 6c4009
	  while (isspace (*line))
Packit 6c4009
	    ++line;
Packit 6c4009
Packit 6c4009
	  result->alias_name = first_unused;
Packit 6c4009
	  while (*line != '\0' && *line != ':')
Packit 6c4009
	    *first_unused++ = *line++;
Packit 6c4009
	  if (*line == '\0' || result->alias_name == first_unused)
Packit 6c4009
	    /* No valid name.  Ignore the line.  */
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  *first_unused++ = '\0';
Packit 6c4009
	  if (room_left < (size_t) (first_unused - result->alias_name))
Packit 6c4009
	    goto no_more_room;
Packit 6c4009
	  room_left -= first_unused - result->alias_name;
Packit 6c4009
	  ++line;
Packit 6c4009
Packit 6c4009
	  /* When we search for a specific alias we can avoid all the
Packit 6c4009
	     difficult parts and compare now with the name we are
Packit 6c4009
	     looking for.  If it does not match we simply ignore all
Packit 6c4009
	     lines until the next line containing the start of a new
Packit 6c4009
	     alias is found.  */
Packit 6c4009
	  ignore = (match != NULL
Packit 6c4009
		    && __strcasecmp (result->alias_name, match) != 0);
Packit 6c4009
Packit 6c4009
	  while (! ignore)
Packit 6c4009
	    {
Packit 6c4009
	      while (isspace (*line))
Packit 6c4009
		++line;
Packit 6c4009
Packit 6c4009
	      cp = first_unused;
Packit 6c4009
	      while (*line != '\0' && *line != ',')
Packit 6c4009
		*first_unused++ = *line++;
Packit 6c4009
Packit 6c4009
	      if (first_unused != cp)
Packit 6c4009
		{
Packit 6c4009
		  /* OK, we can have a regular entry or an include
Packit 6c4009
		     request.  */
Packit 6c4009
		  if (*line != '\0')
Packit 6c4009
		    ++line;
Packit 6c4009
		  *first_unused++ = '\0';
Packit 6c4009
Packit 6c4009
		  if (strncmp (cp, ":include:", 9) != 0)
Packit 6c4009
		    {
Packit 6c4009
		      if (room_left < (first_unused - cp) + sizeof (char *))
Packit 6c4009
			goto no_more_room;
Packit 6c4009
		      room_left -= (first_unused - cp) + sizeof (char *);
Packit 6c4009
Packit 6c4009
		      ++result->alias_members_len;
Packit 6c4009
		    }
Packit 6c4009
		  else
Packit 6c4009
		    {
Packit 6c4009
		      /* Oh well, we have to read the addressed file.  */
Packit 6c4009
		      FILE *listfile;
Packit 6c4009
		      char *old_line = NULL;
Packit 6c4009
Packit 6c4009
		      first_unused = cp;
Packit 6c4009
Packit Service 14e5e5
		      listfile = __nss_files_fopen (&cp[9]);
Packit 6c4009
		      /* If the file does not exist we simply ignore
Packit 6c4009
			 the statement.  */
Packit 6c4009
		      if (listfile != NULL
Packit 6c4009
			  && (old_line = strdup (line)) != NULL)
Packit 6c4009
			{
Packit 6c4009
			  while (! feof_unlocked (listfile))
Packit 6c4009
			    {
Packit Service b0f34f
			      if (room_left < 2)
Packit Service b0f34f
				{
Packit Service b0f34f
				  free (old_line);
Packit Service b0f34f
				  fclose (listfile);
Packit Service b0f34f
				  goto no_more_room;
Packit Service b0f34f
				}
Packit Service b0f34f
Packit 6c4009
			      first_unused[room_left - 1] = '\xff';
Packit 6c4009
			      line = fgets_unlocked (first_unused, room_left,
Packit 6c4009
						     listfile);
Packit 6c4009
			      if (line == NULL)
Packit 6c4009
				break;
Packit 6c4009
			      if (first_unused[room_left - 1] != '\xff')
Packit 6c4009
				{
Packit 6c4009
				  free (old_line);
Packit Service b0f34f
				  fclose (listfile);
Packit 6c4009
				  goto no_more_room;
Packit 6c4009
				}
Packit 6c4009
Packit 6c4009
			      /* Parse the line.  */
Packit 6c4009
			      cp = strpbrk (line, "#\n");
Packit 6c4009
			      if (cp != NULL)
Packit 6c4009
				*cp = '\0';
Packit 6c4009
Packit 6c4009
			      do
Packit 6c4009
				{
Packit 6c4009
				  while (isspace (*line))
Packit 6c4009
				    ++line;
Packit 6c4009
Packit 6c4009
				  cp = first_unused;
Packit 6c4009
				  while (*line != '\0' && *line != ',')
Packit 6c4009
				    *first_unused++ = *line++;
Packit 6c4009
Packit 6c4009
				  if (*line != '\0')
Packit 6c4009
				    ++line;
Packit 6c4009
Packit 6c4009
				  if (first_unused != cp)
Packit 6c4009
				    {
Packit 6c4009
				      *first_unused++ = '\0';
Packit 6c4009
				      if (room_left < ((first_unused - cp)
Packit 6c4009
						       + __alignof__ (char *)))
Packit 6c4009
					{
Packit 6c4009
					  free (old_line);
Packit Service b0f34f
					  fclose (listfile);
Packit 6c4009
					  goto no_more_room;
Packit 6c4009
					}
Packit 6c4009
				      room_left -= ((first_unused - cp)
Packit 6c4009
						    + __alignof__ (char *));
Packit 6c4009
				      ++result->alias_members_len;
Packit 6c4009
				    }
Packit 6c4009
				}
Packit 6c4009
			      while (*line != '\0');
Packit 6c4009
			    }
Packit 6c4009
			  fclose (listfile);
Packit 6c4009
Packit 6c4009
			  first_unused[room_left - 1] = '\0';
Packit 6c4009
			  strncpy (first_unused, old_line, room_left);
Packit 6c4009
Packit 6c4009
			  free (old_line);
Packit 6c4009
			  line = first_unused;
Packit 6c4009
Packit 6c4009
			  if (first_unused[room_left - 1] != '\0')
Packit 6c4009
			    goto no_more_room;
Packit 6c4009
			}
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      if (*line == '\0')
Packit 6c4009
		{
Packit 6c4009
		  /* Get the next line.  But we must be careful.  We
Packit 6c4009
		     must not read the whole line at once since it
Packit 6c4009
		     might belong to the current alias.  Simply read
Packit 6c4009
		     the first character.  If it is a white space we
Packit 6c4009
		     have a continuation line.  Otherwise it is the
Packit 6c4009
		     beginning of a new alias and we can push back the
Packit 6c4009
		     just read character.  */
Packit 6c4009
		  int ch;
Packit 6c4009
Packit 6c4009
		  ch = fgetc_unlocked (stream);
Packit 6c4009
		  if (ch == EOF || ch == '\n' || !isspace (ch))
Packit 6c4009
		    {
Packit 6c4009
		      size_t cnt;
Packit 6c4009
Packit 6c4009
		      /* Now prepare the return.  Provide string
Packit 6c4009
			 pointers for the currently selected aliases.  */
Packit 6c4009
		      if (ch != EOF)
Packit 6c4009
			ungetc (ch, stream);
Packit 6c4009
Packit 6c4009
		      /* Adjust the pointer so it is aligned for
Packit 6c4009
			 storing pointers.  */
Packit 6c4009
		      first_unused += __alignof__ (char *) - 1;
Packit 6c4009
		      first_unused -= ((first_unused - (char *) 0)
Packit 6c4009
				       % __alignof__ (char *));
Packit 6c4009
		      result->alias_members = (char **) first_unused;
Packit 6c4009
Packit 6c4009
		      /* Compute addresses of alias entry strings.  */
Packit 6c4009
		      cp = result->alias_name;
Packit 6c4009
		      for (cnt = 0; cnt < result->alias_members_len; ++cnt)
Packit 6c4009
			{
Packit 6c4009
			  cp = strchr (cp, '\0') + 1;
Packit 6c4009
			  result->alias_members[cnt] = cp;
Packit 6c4009
			}
Packit 6c4009
Packit 6c4009
		      status = (result->alias_members_len == 0
Packit 6c4009
				? NSS_STATUS_RETURN : NSS_STATUS_SUCCESS);
Packit 6c4009
		      break;
Packit 6c4009
		    }
Packit 6c4009
Packit 6c4009
		  /* The just read character is a white space and so
Packit 6c4009
		     can be ignored.  */
Packit 6c4009
		  first_unused[room_left - 1] = '\xff';
Packit 6c4009
		  line = fgets_unlocked (first_unused, room_left, stream);
Packit 6c4009
		  if (first_unused[room_left - 1] != '\xff')
Packit 6c4009
		    goto no_more_room;
Packit 6c4009
		  cp = strpbrk (line, "#\n");
Packit 6c4009
		  if (cp != NULL)
Packit 6c4009
		    *cp = '\0';
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (status != NSS_STATUS_NOTFOUND)
Packit 6c4009
	/* We read something.  In any case break here.  */
Packit 6c4009
	break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_files_getaliasent_r (struct aliasent *result, char *buffer, size_t buflen,
Packit 6c4009
			  int *errnop)
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
    status = internal_setent (&stream);
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      result->alias_local = 1;
Packit 6c4009
Packit 6c4009
      /* Read lines until we get a definite result.  */
Packit 6c4009
      do
Packit 6c4009
	status = get_next_alias (stream, NULL, result, buffer, buflen, errnop);
Packit 6c4009
      while (status == NSS_STATUS_RETURN);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_files_getaliasbyname_r (const char *name, struct aliasent *result,
Packit 6c4009
			     char *buffer, size_t buflen, int *errnop)
Packit 6c4009
{
Packit 6c4009
  /* Return next entry in host file.  */
Packit 6c4009
  enum nss_status status = NSS_STATUS_SUCCESS;
Packit 6c4009
  FILE *stream = NULL;
Packit 6c4009
Packit 6c4009
  if (name == NULL)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (EINVAL);
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Open the stream.  */
Packit 6c4009
  status = internal_setent (&stream);
Packit 6c4009
Packit 6c4009
  if (status == NSS_STATUS_SUCCESS)
Packit 6c4009
    {
Packit 6c4009
      result->alias_local = 1;
Packit 6c4009
Packit 6c4009
      /* Read lines until we get a definite result.  */
Packit 6c4009
      do
Packit 6c4009
	status = get_next_alias (stream, name, result, buffer, buflen, errnop);
Packit 6c4009
      while (status == NSS_STATUS_RETURN);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  internal_endent (&stream);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}