Blame nis/nis_lookup.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@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 <string.h>
Packit 6c4009
#include <rpcsvc/nis.h>
Packit 6c4009
#include "nis_xdr.h"
Packit 6c4009
#include "nis_intern.h"
Packit 6c4009
#include <libnsl.h>
Packit 6c4009
#include <shlib-compat.h>
Packit 6c4009
Packit 6c4009
Packit 6c4009
nis_result *
Packit 6c4009
nis_lookup (const_nis_name name, const unsigned int flags)
Packit 6c4009
{
Packit 6c4009
  nis_result *res = calloc (1, sizeof (nis_result));
Packit 6c4009
  struct ns_request req;
Packit 6c4009
  nis_name *names;
Packit 6c4009
  nis_error status;
Packit 6c4009
  int link_first_try = 0;
Packit 6c4009
  int count_links = 0;	 /* We will follow only 16 links in the deep */
Packit 6c4009
  int done = 0;
Packit 6c4009
  int name_nr = 0;
Packit 6c4009
  nis_name namebuf[2] = {NULL, NULL};
Packit 6c4009
Packit 6c4009
  if (res == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  if ((flags & EXPAND_NAME) && (name[strlen (name) - 1] != '.'))
Packit 6c4009
    {
Packit 6c4009
      names = nis_getnames (name);
Packit 6c4009
      if (names == NULL)
Packit 6c4009
	{
Packit 6c4009
	  NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
Packit 6c4009
	  return res;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      names = namebuf;
Packit 6c4009
      names[0] = (nis_name)name;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  req.ns_name = names[0];
Packit 6c4009
  while (!done)
Packit 6c4009
    {
Packit 6c4009
      dir_binding bptr;
Packit 6c4009
      directory_obj *dir = NULL;
Packit 6c4009
      req.ns_object.ns_object_len = 0;
Packit 6c4009
      req.ns_object.ns_object_val = NULL;
Packit 6c4009
Packit 6c4009
      status = __prepare_niscall (req.ns_name, &dir, &bptr, flags);
Packit 6c4009
      if (__glibc_unlikely (status != NIS_SUCCESS))
Packit 6c4009
	{
Packit 6c4009
	  NIS_RES_STATUS (res) = status;
Packit 6c4009
	  goto out;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
	  static const struct timeval RPCTIMEOUT = {10, 0};
Packit 6c4009
	  enum clnt_stat result;
Packit 6c4009
Packit 6c4009
	again:
Packit 6c4009
	  result = clnt_call (bptr.clnt, NIS_LOOKUP,
Packit 6c4009
			      (xdrproc_t) _xdr_ns_request,
Packit 6c4009
			      (caddr_t) &req, (xdrproc_t) _xdr_nis_result,
Packit 6c4009
			      (caddr_t) res, RPCTIMEOUT);
Packit 6c4009
Packit 6c4009
	  if (result != RPC_SUCCESS)
Packit 6c4009
	    status = NIS_RPCERROR;
Packit 6c4009
	  else
Packit 6c4009
	    {
Packit 6c4009
	      status = NIS_SUCCESS;
Packit 6c4009
Packit 6c4009
	      if (NIS_RES_STATUS (res) == NIS_SUCCESS)
Packit 6c4009
		{
Packit 6c4009
		    if (__type_of (NIS_RES_OBJECT (res)) == NIS_LINK_OBJ
Packit 6c4009
			&& (flags & FOLLOW_LINKS)) /* We are following links */
Packit 6c4009
		      {
Packit 6c4009
			/* if we hit the link limit, bail */
Packit 6c4009
			if (count_links > NIS_MAXLINKS)
Packit 6c4009
			  {
Packit 6c4009
			    NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
Packit 6c4009
			    break;
Packit 6c4009
			  }
Packit 6c4009
			++count_links;
Packit 6c4009
			req.ns_name =
Packit 6c4009
			  strdupa (NIS_RES_OBJECT (res)->LI_data.li_name);
Packit 6c4009
Packit 6c4009
			/* The following is a non-obvious optimization.  A
Packit 6c4009
			   nis_freeresult call would call xdr_free as the
Packit 6c4009
			   following code.  But it also would unnecessarily
Packit 6c4009
			   free the result structure.  We avoid this here
Packit 6c4009
			   along with the necessary tests.  */
Packit 6c4009
			xdr_free ((xdrproc_t) _xdr_nis_result, (char *) res);
Packit 6c4009
			memset (res, '\0', sizeof (*res));
Packit 6c4009
Packit 6c4009
			link_first_try = 1; /* Try at first the old binding */
Packit 6c4009
			goto again;
Packit 6c4009
		      }
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		if (NIS_RES_STATUS (res) == NIS_SYSTEMERROR
Packit 6c4009
		    || NIS_RES_STATUS (res) == NIS_NOSUCHNAME
Packit 6c4009
		    || NIS_RES_STATUS (res) == NIS_NOT_ME)
Packit 6c4009
		  {
Packit 6c4009
		    if (link_first_try)
Packit 6c4009
		      {
Packit 6c4009
			__nisbind_destroy (&bptr);
Packit 6c4009
			nis_free_directory (dir);
Packit 6c4009
			/* Otherwise __nisfind_server will not do anything.  */
Packit 6c4009
			dir = NULL;
Packit 6c4009
Packit 6c4009
			if (__nisfind_server (req.ns_name, 1, &dir, &bptr,
Packit 6c4009
					      flags & ~MASTER_ONLY)
Packit 6c4009
			    != NIS_SUCCESS)
Packit 6c4009
			  goto out;
Packit 6c4009
		      }
Packit 6c4009
		    else
Packit 6c4009
		      if (__nisbind_next (&bptr) != NIS_SUCCESS)
Packit 6c4009
			{
Packit 6c4009
			  /* No more servers to search.  Try parent.  */
Packit 6c4009
			  const char *ndomain = __nis_domain_of (req.ns_name);
Packit 6c4009
			  req.ns_name = strdupa (ndomain);
Packit 6c4009
			  if (strcmp (req.ns_name, ".") == 0)
Packit 6c4009
			    {
Packit 6c4009
			      NIS_RES_STATUS (res) = NIS_NAMEUNREACHABLE;
Packit 6c4009
			      goto out;
Packit 6c4009
			    }
Packit 6c4009
Packit 6c4009
			  __nisbind_destroy (&bptr);
Packit 6c4009
			  nis_free_directory (dir);
Packit 6c4009
			  dir = NULL;
Packit 6c4009
			  status = __prepare_niscall (req.ns_name, &dir,
Packit 6c4009
						      &bptr, flags);
Packit 6c4009
			  if (__glibc_unlikely (status != NIS_SUCCESS))
Packit 6c4009
			    {
Packit 6c4009
			      NIS_RES_STATUS (res) = status;
Packit 6c4009
			      goto out;
Packit 6c4009
			    }
Packit 6c4009
			  goto again;
Packit 6c4009
			}
Packit 6c4009
Packit 6c4009
		    while (__nisbind_connect (&bptr) != NIS_SUCCESS)
Packit 6c4009
		      {
Packit 6c4009
			if (__nisbind_next (&bptr) != NIS_SUCCESS)
Packit 6c4009
			  {
Packit 6c4009
			    nis_free_directory (dir);
Packit 6c4009
			    goto out;
Packit 6c4009
			  }
Packit 6c4009
		      }
Packit 6c4009
		    goto again;
Packit 6c4009
		  }
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  link_first_try = 0; /* Set it back */
Packit 6c4009
	}
Packit 6c4009
      while ((flags & HARD_LOOKUP) && status == NIS_RPCERROR);
Packit 6c4009
Packit 6c4009
      __nisbind_destroy (&bptr);
Packit 6c4009
      nis_free_directory (dir);
Packit 6c4009
Packit 6c4009
      if (status != NIS_SUCCESS)
Packit 6c4009
	{
Packit 6c4009
	  NIS_RES_STATUS (res) = status;
Packit 6c4009
	  goto out;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      switch (NIS_RES_STATUS (res))
Packit 6c4009
	{
Packit 6c4009
	case NIS_PARTIAL:
Packit 6c4009
	case NIS_SUCCESS:
Packit 6c4009
	case NIS_S_SUCCESS:
Packit 6c4009
	case NIS_LINKNAMEERROR: /* We follow to max links */
Packit 6c4009
	case NIS_UNAVAIL: /* NIS+ is not installed, or all servers are down */
Packit 6c4009
	  ++done;
Packit 6c4009
	  break;
Packit 6c4009
	default:
Packit 6c4009
	  /* Try the next domainname if we don't follow a link */
Packit 6c4009
	  if (count_links)
Packit 6c4009
	    {
Packit 6c4009
	      free (req.ns_name);
Packit 6c4009
	      NIS_RES_STATUS (res) = NIS_LINKNAMEERROR;
Packit 6c4009
	      ++done;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  ++name_nr;
Packit 6c4009
	  if (names[name_nr] == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      ++done;
Packit 6c4009
	      break;
Packit 6c4009
	    }
Packit 6c4009
	  req.ns_name = names[name_nr];
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
 out:
Packit 6c4009
  if (names != namebuf)
Packit 6c4009
    nis_freenames (names);
Packit 6c4009
Packit 6c4009
  return res;
Packit 6c4009
}
Packit 6c4009
libnsl_hidden_nolink_def (nis_lookup, GLIBC_2_1)