Blame nis/nss_nisplus/nisplus-network.c

Packit 6c4009
/* Copyright (C) 1997-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Thorsten Kukuk <kukuk@vt.uni-paderborn.de>, 1997.
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 <atomic.h>
Packit 6c4009
#include <ctype.h>
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include <nss.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <arpa/inet.h>
Packit 6c4009
#include <rpcsvc/nis.h>
Packit 6c4009
#include <libc-lock.h>
Packit 6c4009
Packit 6c4009
#include "nss-nisplus.h"
Packit 6c4009
Packit 6c4009
__libc_lock_define_initialized (static, lock)
Packit 6c4009
Packit 6c4009
static nis_result *result;
Packit 6c4009
static nis_name tablename_val;
Packit 6c4009
static u_long tablename_len;
Packit 6c4009
Packit 6c4009
#define NISENTRYVAL(idx, col, res) \
Packit 6c4009
        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_val)
Packit 6c4009
Packit 6c4009
#define NISENTRYLEN(idx, col, res) \
Packit 6c4009
        (NIS_RES_OBJECT (res)[idx].EN_data.en_cols.en_cols_val[col].ec_value.ec_value_len)
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
_nss_nisplus_parse_netent (nis_result *result, struct netent *network,
Packit 6c4009
			   char *buffer, size_t buflen, int *errnop)
Packit 6c4009
{
Packit 6c4009
  char *first_unused = buffer;
Packit 6c4009
  size_t room_left = buflen;
Packit 6c4009
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  if ((result->status != NIS_SUCCESS && result->status != NIS_S_SUCCESS)
Packit 6c4009
      || __type_of (NIS_RES_OBJECT (result)) != NIS_ENTRY_OBJ
Packit 6c4009
      || strcmp (NIS_RES_OBJECT (result)[0].EN_data.en_type,
Packit 6c4009
		 "networks_tbl") != 0
Packit 6c4009
      || NIS_RES_OBJECT (result)[0].EN_data.en_cols.en_cols_len < 3)
Packit 6c4009
    return 0;
Packit 6c4009
Packit 6c4009
  if (NISENTRYLEN (0, 0, result) >= room_left)
Packit 6c4009
    {
Packit 6c4009
      /* The line is too long for our buffer.  */
Packit 6c4009
    no_more_room:
Packit 6c4009
      *errnop = ERANGE;
Packit 6c4009
      return -1;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  strncpy (first_unused, NISENTRYVAL (0, 0, result),
Packit 6c4009
           NISENTRYLEN (0, 0, result));
Packit 6c4009
  first_unused[NISENTRYLEN (0, 0, result)] = '\0';
Packit 6c4009
  network->n_name = first_unused;
Packit 6c4009
  size_t len = strlen (first_unused) + 1;
Packit 6c4009
  room_left -= len;
Packit 6c4009
  first_unused += len;
Packit 6c4009
Packit 6c4009
  network->n_addrtype = 0;
Packit 6c4009
  network->n_net = inet_network (NISENTRYVAL (0, 2, result));
Packit 6c4009
Packit 6c4009
  /* XXX Rewrite at some point to allocate the array first and then
Packit 6c4009
     copy the strings.  It wasteful to first concatenate the strings
Packit 6c4009
     to just split them again later.  */
Packit 6c4009
  char *line = first_unused;
Packit 6c4009
  for (unsigned int i = 0; i < NIS_RES_NUMOBJ (result); ++i)
Packit 6c4009
    {
Packit 6c4009
      if (strcmp (NISENTRYVAL (i, 1, result), network->n_name) != 0)
Packit 6c4009
        {
Packit 6c4009
          if (NISENTRYLEN (i, 1, result) + 2 > room_left)
Packit 6c4009
	    goto no_more_room;
Packit 6c4009
Packit 6c4009
	  *first_unused++ = ' ';
Packit 6c4009
          first_unused = __stpncpy (first_unused, NISENTRYVAL (i, 1, result),
Packit 6c4009
				    NISENTRYLEN (i, 1, result));
Packit 6c4009
          room_left -= (NISENTRYLEN (i, 1, result) + 1);
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
  *first_unused++ = '\0';
Packit 6c4009
Packit 6c4009
  /* Adjust the pointer so it is aligned for
Packit 6c4009
     storing pointers.  */
Packit 6c4009
  size_t adjust = ((__alignof__ (char *)
Packit 6c4009
		    - (first_unused - (char *) 0) % __alignof__ (char *))
Packit 6c4009
		   % __alignof__ (char *));
Packit 6c4009
  if (room_left < adjust + sizeof (char *))
Packit 6c4009
    goto no_more_room;
Packit 6c4009
  first_unused += adjust;
Packit 6c4009
  room_left -= adjust;
Packit 6c4009
  network->n_aliases = (char **) first_unused;
Packit 6c4009
Packit 6c4009
  /* For the terminating NULL pointer.  */
Packit 6c4009
  room_left -= sizeof (char *);
Packit 6c4009
Packit 6c4009
  unsigned int i = 0;
Packit 6c4009
  while (*line != '\0')
Packit 6c4009
    {
Packit 6c4009
      /* Skip leading blanks.  */
Packit 6c4009
      while (isspace (*line))
Packit 6c4009
        ++line;
Packit 6c4009
Packit 6c4009
      if (*line == '\0')
Packit 6c4009
        break;
Packit 6c4009
Packit 6c4009
      if (room_left < sizeof (char *))
Packit 6c4009
	goto no_more_room;
Packit 6c4009
Packit 6c4009
      room_left -= sizeof (char *);
Packit 6c4009
      network->n_aliases[i++] = line;
Packit 6c4009
Packit 6c4009
      while (*line != '\0' && *line != ' ')
Packit 6c4009
        ++line;
Packit 6c4009
Packit 6c4009
      if (*line == ' ')
Packit 6c4009
	*line++ = '\0';
Packit 6c4009
    }
Packit 6c4009
  network->n_aliases[i] = NULL;
Packit 6c4009
Packit 6c4009
  return 1;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static enum nss_status
Packit 6c4009
_nss_create_tablename (int *errnop)
Packit 6c4009
{
Packit 6c4009
  if (tablename_val == NULL)
Packit 6c4009
    {
Packit 6c4009
      const char *local_dir = nis_local_directory ();
Packit 6c4009
      size_t local_dir_len = strlen (local_dir);
Packit 6c4009
      static const char prefix[] = "networks.org_dir.";
Packit 6c4009
Packit 6c4009
      char *p = malloc (sizeof (prefix) + local_dir_len);
Packit 6c4009
      if (p == NULL)
Packit 6c4009
	{
Packit 6c4009
	  *errnop = errno;
Packit 6c4009
	  return NSS_STATUS_TRYAGAIN;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      memcpy (__stpcpy (p, prefix), local_dir, local_dir_len + 1);
Packit 6c4009
Packit 6c4009
      tablename_len = sizeof (prefix) - 1 + local_dir_len;
Packit 6c4009
Packit 6c4009
      atomic_write_barrier ();
Packit 6c4009
Packit 6c4009
      tablename_val = p;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_setnetent (int stayopen)
Packit 6c4009
{
Packit 6c4009
  enum nss_status status = NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
  if (result != NULL)
Packit 6c4009
    {
Packit 6c4009
      nis_freeresult (result);
Packit 6c4009
      result = NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (tablename_val == NULL)
Packit 6c4009
    {
Packit 6c4009
      int err;
Packit 6c4009
      status = _nss_create_tablename (&err;;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_endnetent (void)
Packit 6c4009
{
Packit 6c4009
  __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
  if (result != NULL)
Packit 6c4009
    {
Packit 6c4009
      nis_freeresult (result);
Packit 6c4009
      result = NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
static enum nss_status
Packit 6c4009
internal_nisplus_getnetent_r (struct netent *network, char *buffer,
Packit 6c4009
			       size_t buflen, int *errnop, int *herrnop)
Packit 6c4009
{
Packit 6c4009
  int parse_res;
Packit 6c4009
Packit 6c4009
  /* Get the next entry until we found a correct one. */
Packit 6c4009
  do
Packit 6c4009
    {
Packit 6c4009
      nis_result *saved_res;
Packit 6c4009
Packit 6c4009
      if (result == NULL)
Packit 6c4009
	{
Packit 6c4009
	  saved_res = NULL;
Packit 6c4009
Packit 6c4009
	  if (tablename_val == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      enum nss_status status = _nss_create_tablename (errnop);
Packit 6c4009
Packit 6c4009
	      if (status != NSS_STATUS_SUCCESS)
Packit 6c4009
		return status;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  result = nis_first_entry (tablename_val);
Packit 6c4009
	  if (result == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      *errnop = errno;
Packit 6c4009
	      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
	    }
Packit 6c4009
	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
Packit 6c4009
	    {
Packit 6c4009
	      int retval = niserr2nss (result->status);
Packit 6c4009
	      nis_freeresult (result);
Packit 6c4009
	      result = NULL;
Packit 6c4009
	      if (retval == NSS_STATUS_TRYAGAIN)
Packit 6c4009
		{
Packit 6c4009
		  *herrnop = NETDB_INTERNAL;
Packit 6c4009
		  *errnop = errno;
Packit 6c4009
		  return retval;
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		return retval;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  saved_res = result;
Packit 6c4009
	  result = nis_next_entry (tablename_val, &result->cookie);
Packit 6c4009
	  if (result == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      *errnop = errno;
Packit 6c4009
	      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
	    }
Packit 6c4009
	  if (niserr2nss (result->status) != NSS_STATUS_SUCCESS)
Packit 6c4009
	    {
Packit 6c4009
	      int retval = niserr2nss (result->status);
Packit 6c4009
	      nis_freeresult (result);
Packit 6c4009
	      result = saved_res;
Packit 6c4009
	      if (retval == NSS_STATUS_TRYAGAIN)
Packit 6c4009
		{
Packit 6c4009
		  *herrnop = NETDB_INTERNAL;
Packit 6c4009
		  *errnop = errno;
Packit 6c4009
		}
Packit 6c4009
	      return retval;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      parse_res = _nss_nisplus_parse_netent (result, network, buffer,
Packit 6c4009
					     buflen, errnop);
Packit 6c4009
      if (parse_res == -1)
Packit 6c4009
        {
Packit 6c4009
          *herrnop = NETDB_INTERNAL;
Packit 6c4009
          return NSS_STATUS_TRYAGAIN;
Packit 6c4009
        }
Packit 6c4009
Packit 6c4009
    }
Packit 6c4009
  while (!parse_res);
Packit 6c4009
Packit 6c4009
  return NSS_STATUS_SUCCESS;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_getnetent_r (struct netent *result, char *buffer,
Packit 6c4009
			   size_t buflen, int *errnop, int *herrnop)
Packit 6c4009
{
Packit 6c4009
  int status;
Packit 6c4009
Packit 6c4009
  __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
  status = internal_nisplus_getnetent_r (result, buffer, buflen, errnop,
Packit 6c4009
					 herrnop);
Packit 6c4009
Packit 6c4009
  __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
  return status;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_getnetbyname_r (const char *name, struct netent *network,
Packit 6c4009
			      char *buffer, size_t buflen, int *errnop,
Packit 6c4009
			     int *herrnop)
Packit 6c4009
{
Packit 6c4009
  int parse_res, retval;
Packit 6c4009
Packit 6c4009
  if (tablename_val == NULL)
Packit 6c4009
    {
Packit 6c4009
      __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
      enum nss_status status = _nss_create_tablename (errnop);
Packit 6c4009
Packit 6c4009
      __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
      if (status != NSS_STATUS_SUCCESS)
Packit 6c4009
	return status;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (name == NULL)
Packit 6c4009
    {
Packit 6c4009
      *errnop = EINVAL;
Packit 6c4009
      *herrnop = NETDB_INTERNAL;
Packit 6c4009
      return NSS_STATUS_UNAVAIL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  nis_result *result;
Packit 6c4009
  char buf[strlen (name) + 10 + tablename_len];
Packit 6c4009
  int olderr = errno;
Packit 6c4009
Packit 6c4009
  /* Search at first in the alias list, and use the correct name
Packit 6c4009
     for the next search */
Packit 6c4009
  snprintf (buf, sizeof (buf), "[name=%s],%s", name, tablename_val);
Packit 6c4009
  result = nis_list (buf, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM, NULL, NULL);
Packit 6c4009
Packit 6c4009
  if (result != NULL)
Packit 6c4009
    {
Packit 6c4009
      char *bufptr = buf;
Packit 6c4009
Packit 6c4009
      /* If we do not find it, try it as original name. But if the
Packit 6c4009
	 database is correct, we should find it in the first case, too */
Packit 6c4009
      if ((result->status != NIS_SUCCESS
Packit 6c4009
	   && result->status != NIS_S_SUCCESS)
Packit 6c4009
	  || __type_of (result->objects.objects_val) != NIS_ENTRY_OBJ
Packit 6c4009
	  || strcmp (result->objects.objects_val[0].EN_data.en_type,
Packit 6c4009
		     "networks_tbl") != 0
Packit 6c4009
	  || (result->objects.objects_val[0].EN_data.en_cols.en_cols_len
Packit 6c4009
	      < 3))
Packit 6c4009
	snprintf (buf, sizeof (buf), "[cname=%s],%s", name, tablename_val);
Packit 6c4009
      else
Packit 6c4009
	{
Packit 6c4009
	  /* We need to allocate a new buffer since there is no
Packit 6c4009
	     guarantee the returned name has a length limit.  */
Packit 6c4009
	  const char *entryval = NISENTRYVAL (0, 0, result);
Packit 6c4009
	  size_t buflen = strlen (entryval) + 10 + tablename_len;
Packit 6c4009
	  bufptr = alloca (buflen);
Packit 6c4009
	  snprintf (bufptr, buflen, "[cname=%s],%s",
Packit 6c4009
		    entryval, tablename_val);
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      nis_freeresult (result);
Packit 6c4009
      result = nis_list (bufptr, FOLLOW_LINKS | FOLLOW_PATH | USE_DGRAM,
Packit 6c4009
			 NULL, NULL);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (result == NULL)
Packit 6c4009
    {
Packit 6c4009
      __set_errno (ENOMEM);
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  retval = niserr2nss (result->status);
Packit 6c4009
  if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS))
Packit 6c4009
    {
Packit 6c4009
      if (retval == NSS_STATUS_TRYAGAIN)
Packit 6c4009
	{
Packit 6c4009
	  *errnop = errno;
Packit 6c4009
	  *herrnop = NETDB_INTERNAL;
Packit 6c4009
	}
Packit 6c4009
      else
Packit 6c4009
	__set_errno (olderr);
Packit 6c4009
      nis_freeresult (result);
Packit 6c4009
      return retval;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  parse_res = _nss_nisplus_parse_netent (result, network, buffer, buflen,
Packit 6c4009
					 errnop);
Packit 6c4009
Packit 6c4009
  nis_freeresult (result);
Packit 6c4009
Packit 6c4009
  if (parse_res > 0)
Packit 6c4009
    return NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
  *herrnop = NETDB_INTERNAL;
Packit 6c4009
  if (parse_res == -1)
Packit 6c4009
    {
Packit 6c4009
      *errnop = ERANGE;
Packit 6c4009
      return NSS_STATUS_TRYAGAIN;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __set_errno (olderr);
Packit 6c4009
  return NSS_STATUS_NOTFOUND;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* XXX type is ignored, SUN's NIS+ table doesn't support it */
Packit 6c4009
enum nss_status
Packit 6c4009
_nss_nisplus_getnetbyaddr_r (uint32_t addr, const int type,
Packit 6c4009
			     struct netent *network, char *buffer,
Packit 6c4009
			     size_t buflen, int *errnop, int *herrnop)
Packit 6c4009
{
Packit 6c4009
  if (tablename_val == NULL)
Packit 6c4009
    {
Packit 6c4009
      __libc_lock_lock (lock);
Packit 6c4009
Packit 6c4009
      enum nss_status status = _nss_create_tablename (errnop);
Packit 6c4009
Packit 6c4009
      __libc_lock_unlock (lock);
Packit 6c4009
Packit 6c4009
      if (status != NSS_STATUS_SUCCESS)
Packit 6c4009
	return status;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  {
Packit 6c4009
    char buf[27 + tablename_len];
Packit 6c4009
    char buf2[18];
Packit 6c4009
    int olderr = errno;
Packit 6c4009
Packit 6c4009
    struct in_addr in = { .s_addr = htonl (addr) };
Packit 6c4009
    strcpy (buf2, inet_ntoa (in));
Packit 6c4009
    size_t b2len = strlen (buf2);
Packit 6c4009
Packit 6c4009
    while (1)
Packit 6c4009
      {
Packit 6c4009
	snprintf (buf, sizeof (buf), "[addr=%s],%s", buf2, tablename_val);
Packit 6c4009
	nis_result *result = nis_list (buf, EXPAND_NAME | USE_DGRAM,
Packit 6c4009
				       NULL, NULL);
Packit 6c4009
Packit 6c4009
	if (result == NULL)
Packit 6c4009
	  {
Packit 6c4009
	    __set_errno (ENOMEM);
Packit 6c4009
	    return NSS_STATUS_TRYAGAIN;
Packit 6c4009
	  }
Packit 6c4009
	enum nss_status retval = niserr2nss (result->status);
Packit 6c4009
	if (__glibc_unlikely (retval != NSS_STATUS_SUCCESS))
Packit 6c4009
	  {
Packit 6c4009
	    if (b2len > 2 && buf2[b2len - 2] == '.' && buf2[b2len - 1] == '0')
Packit 6c4009
	      {
Packit 6c4009
		/* Try again, but with trailing dot(s)
Packit 6c4009
		   removed (one by one) */
Packit 6c4009
		buf2[b2len - 2] = '\0';
Packit 6c4009
		b2len -= 2;
Packit 6c4009
		nis_freeresult (result);
Packit 6c4009
		continue;
Packit 6c4009
	      }
Packit 6c4009
Packit 6c4009
	    if (retval == NSS_STATUS_TRYAGAIN)
Packit 6c4009
	      {
Packit 6c4009
		*errnop = errno;
Packit 6c4009
		*herrnop = NETDB_INTERNAL;
Packit 6c4009
	      }
Packit 6c4009
	    else
Packit 6c4009
	      __set_errno (olderr);
Packit 6c4009
	    nis_freeresult (result);
Packit 6c4009
	    return retval;
Packit 6c4009
	  }
Packit 6c4009
Packit 6c4009
	int parse_res = _nss_nisplus_parse_netent (result, network, buffer,
Packit 6c4009
						   buflen, errnop);
Packit 6c4009
Packit 6c4009
	nis_freeresult (result);
Packit 6c4009
Packit 6c4009
	if (parse_res > 0)
Packit 6c4009
	  return NSS_STATUS_SUCCESS;
Packit 6c4009
Packit 6c4009
	*herrnop = NETDB_INTERNAL;
Packit 6c4009
	if (parse_res == -1)
Packit 6c4009
	  {
Packit 6c4009
	    *errnop = ERANGE;
Packit 6c4009
	    return NSS_STATUS_TRYAGAIN;
Packit 6c4009
	  }
Packit 6c4009
	else
Packit 6c4009
	  {
Packit 6c4009
	    __set_errno (olderr);
Packit 6c4009
	    return NSS_STATUS_NOTFOUND;
Packit 6c4009
	  }
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
}