Blame nss/getnssent_r.c

Packit 6c4009
/* Copyright (C) 2000-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 <errno.h>
Packit 6c4009
#include <netdb.h>
Packit 6c4009
#include "nsswitch.h"
Packit 6c4009
#include <resolv/resolv_context.h>
Packit 6c4009
Packit 6c4009
/* Set up NIP to run through the services.  If ALL is zero, use NIP's
Packit 6c4009
   current location if it's not nil.  Return nonzero if there are no
Packit 6c4009
   services (left).  */
Packit 6c4009
static int
Packit 6c4009
setup (const char *func_name, db_lookup_function lookup_fct,
Packit 6c4009
       void **fctp, service_user **nip, service_user **startp, int all)
Packit 6c4009
{
Packit 6c4009
  int no_more;
Packit 6c4009
  if (*startp == NULL)
Packit 6c4009
    {
Packit 6c4009
      no_more = lookup_fct (nip, func_name, NULL, fctp);
Packit 6c4009
      *startp = no_more ? (service_user *) -1l : *nip;
Packit 6c4009
    }
Packit 6c4009
  else if (*startp == (service_user *) -1l)
Packit 6c4009
    /* No services at all.  */
Packit 6c4009
    return 1;
Packit 6c4009
  else
Packit 6c4009
    {
Packit 6c4009
      if (all || !*nip)
Packit 6c4009
	/* Reset to the beginning of the service list.  */
Packit 6c4009
	*nip = *startp;
Packit 6c4009
      /* Look up the first function.  */
Packit 6c4009
      no_more = __nss_lookup (nip, func_name, NULL, fctp);
Packit 6c4009
    }
Packit 6c4009
  return no_more;
Packit 6c4009
}
Packit 6c4009

Packit 6c4009
void
Packit 6c4009
__nss_setent (const char *func_name, db_lookup_function lookup_fct,
Packit 6c4009
	      service_user **nip, service_user **startp,
Packit 6c4009
	      service_user **last_nip, int stayopen, int *stayopen_tmp,
Packit 6c4009
	      int res)
Packit 6c4009
{
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    setent_function f;
Packit 6c4009
    void *ptr;
Packit 6c4009
  } fct;
Packit 6c4009
  int no_more;
Packit 6c4009
Packit 6c4009
  struct resolv_context *res_ctx = NULL;
Packit 6c4009
  if (res)
Packit 6c4009
    {
Packit 6c4009
      res_ctx = __resolv_context_get ();
Packit 6c4009
      if (res_ctx == NULL)
Packit 6c4009
	{
Packit 6c4009
	  __set_h_errno (NETDB_INTERNAL);
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Cycle through the services and run their `setXXent' functions until
Packit 6c4009
     we find an available service.  */
Packit 6c4009
  no_more = setup (func_name, lookup_fct, &fct.ptr, nip,
Packit 6c4009
		   startp, 1);
Packit 6c4009
  while (! no_more)
Packit 6c4009
    {
Packit 6c4009
      int is_last_nip = *nip == *last_nip;
Packit 6c4009
      enum nss_status status;
Packit 6c4009
Packit 6c4009
      if (stayopen_tmp)
Packit 6c4009
	status = DL_CALL_FCT (fct.f, (*stayopen_tmp));
Packit 6c4009
      else
Packit 6c4009
	status = DL_CALL_FCT (fct.f, (0));
Packit 6c4009
Packit 6c4009
Packit 6c4009
      /* This is a special-case.  When [SUCCESS=merge] is in play,
Packit 6c4009
         _nss_next2() will skip to the next database.  Due to the
Packit 6c4009
         implementation of that function, we can't know whether we're
Packit 6c4009
         in an enumeration or an individual lookup, which behaves
Packit 6c4009
         differently with regards to merging.  We'll treat SUCCESS as
Packit 6c4009
         an indication to start the enumeration at this database. */
Packit 6c4009
      if (nss_next_action (*nip, status) == NSS_ACTION_MERGE)
Packit 6c4009
	no_more = 1;
Packit 6c4009
      else
Packit 6c4009
	no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
Packit 6c4009
Packit 6c4009
      if (is_last_nip)
Packit 6c4009
	*last_nip = *nip;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __resolv_context_put (res_ctx);
Packit 6c4009
Packit 6c4009
  if (stayopen_tmp)
Packit 6c4009
    *stayopen_tmp = stayopen;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
__nss_endent (const char *func_name, db_lookup_function lookup_fct,
Packit 6c4009
	      service_user **nip, service_user **startp,
Packit 6c4009
	      service_user **last_nip, int res)
Packit 6c4009
{
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    endent_function f;
Packit 6c4009
    void *ptr;
Packit 6c4009
  } fct;
Packit 6c4009
  int no_more;
Packit 6c4009
Packit 6c4009
  struct resolv_context *res_ctx = NULL;
Packit 6c4009
  if (res)
Packit 6c4009
    {
Packit 6c4009
      res_ctx = __resolv_context_get ();
Packit 6c4009
      if (res_ctx == NULL)
Packit 6c4009
	{
Packit 6c4009
	  __set_h_errno (NETDB_INTERNAL);
Packit 6c4009
	  return;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Cycle through all the services and run their endXXent functions.  */
Packit 6c4009
  no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
Packit 6c4009
  while (! no_more)
Packit 6c4009
    {
Packit 6c4009
      /* Ignore status, we force check in __NSS_NEXT.  */
Packit 6c4009
      DL_CALL_FCT (fct.f, ());
Packit 6c4009
Packit 6c4009
      if (*nip == *last_nip)
Packit 6c4009
	/* We have processed all services which were used.  */
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1);
Packit 6c4009
    }
Packit 6c4009
  *last_nip = *nip = NULL;
Packit 6c4009
Packit 6c4009
  __resolv_context_put (res_ctx);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
int
Packit 6c4009
__nss_getent_r (const char *getent_func_name,
Packit 6c4009
		const char *setent_func_name,
Packit 6c4009
		db_lookup_function lookup_fct,
Packit 6c4009
		service_user **nip, service_user **startp,
Packit 6c4009
		service_user **last_nip, int *stayopen_tmp, int res,
Packit 6c4009
		void *resbuf, char *buffer, size_t buflen,
Packit 6c4009
		void **result, int *h_errnop)
Packit 6c4009
{
Packit 6c4009
  union
Packit 6c4009
  {
Packit 6c4009
    getent_function f;
Packit 6c4009
    void *ptr;
Packit 6c4009
  } fct;
Packit 6c4009
  int no_more;
Packit 6c4009
  enum nss_status status;
Packit 6c4009
Packit 6c4009
  struct resolv_context *res_ctx = NULL;
Packit 6c4009
  if (res)
Packit 6c4009
    {
Packit 6c4009
      res_ctx = __resolv_context_get ();
Packit 6c4009
      if (res_ctx == NULL)
Packit 6c4009
	{
Packit 6c4009
	  *h_errnop = NETDB_INTERNAL;
Packit 6c4009
	  *result = NULL;
Packit 6c4009
	  return errno;
Packit 6c4009
	}
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Initialize status to return if no more functions are found.  */
Packit 6c4009
  status = NSS_STATUS_NOTFOUND;
Packit 6c4009
Packit 6c4009
  /* Run through available functions, starting with the same function last
Packit 6c4009
     run.  We will repeat each function as long as it succeeds, and then go
Packit 6c4009
     on to the next service action.  */
Packit 6c4009
  no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip,
Packit 6c4009
		   startp, 0);
Packit 6c4009
  while (! no_more)
Packit 6c4009
    {
Packit 6c4009
      int is_last_nip = *nip == *last_nip;
Packit 6c4009
Packit 6c4009
      status = DL_CALL_FCT (fct.f,
Packit 6c4009
			    (resbuf, buffer, buflen, &errno, &h_errno));
Packit 6c4009
Packit 6c4009
      /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
Packit 6c4009
	 provided buffer is too small.  In this case we should give
Packit 6c4009
	 the user the possibility to enlarge the buffer and we should
Packit 6c4009
	 not simply go on with the next service (even if the TRYAGAIN
Packit 6c4009
	 action tells us so).  */
Packit 6c4009
      if (status == NSS_STATUS_TRYAGAIN
Packit 6c4009
	  && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)
Packit 6c4009
	  && errno == ERANGE)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      do
Packit 6c4009
	{
Packit 6c4009
        /* This is a special-case.  When [SUCCESS=merge] is in play,
Packit 6c4009
           _nss_next2() will skip to the next database.  Due to the
Packit 6c4009
           implementation of that function, we can't know whether we're
Packit 6c4009
           in an enumeration or an individual lookup, which behaves
Packit 6c4009
           differently with regards to merging.  We'll treat SUCCESS as
Packit 6c4009
           an indication to return the results here. */
Packit 6c4009
	  if (status == NSS_STATUS_SUCCESS
Packit 6c4009
	      && nss_next_action (*nip, status) == NSS_ACTION_MERGE)
Packit 6c4009
	    no_more = 1;
Packit 6c4009
	  else
Packit 6c4009
	    no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
Packit 6c4009
				   status, 0);
Packit 6c4009
Packit 6c4009
	  if (is_last_nip)
Packit 6c4009
	    *last_nip = *nip;
Packit 6c4009
Packit 6c4009
	  if (! no_more)
Packit 6c4009
	    {
Packit 6c4009
	      /* Call the `setXXent' function.  This wasn't done before.  */
Packit 6c4009
	      union
Packit 6c4009
	      {
Packit 6c4009
		setent_function f;
Packit 6c4009
		void *ptr;
Packit 6c4009
	      } sfct;
Packit 6c4009
Packit 6c4009
	      no_more = __nss_lookup (nip, setent_func_name, NULL, &sfct.ptr);
Packit 6c4009
Packit 6c4009
	      if (! no_more)
Packit 6c4009
	        {
Packit 6c4009
		  if (stayopen_tmp)
Packit 6c4009
		    status = DL_CALL_FCT (sfct.f, (*stayopen_tmp));
Packit 6c4009
		  else
Packit 6c4009
		    status = DL_CALL_FCT (sfct.f, (0));
Packit 6c4009
		}
Packit 6c4009
	      else
Packit 6c4009
		status = NSS_STATUS_NOTFOUND;
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
      while (! no_more && status != NSS_STATUS_SUCCESS);
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  __resolv_context_put (res_ctx);
Packit 6c4009
Packit 6c4009
  *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
Packit 6c4009
  return (status == NSS_STATUS_SUCCESS ? 0
Packit 6c4009
	  : status != NSS_STATUS_TRYAGAIN ? ENOENT
Packit 6c4009
	  /* h_errno functions only set errno if h_errno is NETDB_INTERNAL.  */
Packit 6c4009
	  : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno
Packit 6c4009
	  : EAGAIN);
Packit 6c4009
}