mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-03 20:53:13 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			216 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			216 lines
		
	
	
		
			5.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 2000, 2002, 2004, 2007, 2011 Free Software Foundation, Inc.
 | 
						||
   This file is part of the GNU C Library.
 | 
						||
 | 
						||
   The GNU C Library is free software; you can redistribute it and/or
 | 
						||
   modify it under the terms of the GNU Lesser General Public
 | 
						||
   License as published by the Free Software Foundation; either
 | 
						||
   version 2.1 of the License, or (at your option) any later version.
 | 
						||
 | 
						||
   The GNU C Library is distributed in the hope that it will be useful,
 | 
						||
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						||
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						||
   Lesser General Public License for more details.
 | 
						||
 | 
						||
   You should have received a copy of the GNU Lesser General Public
 | 
						||
   License along with the GNU C Library; if not, see
 | 
						||
   <http://www.gnu.org/licenses/>.  */
 | 
						||
 | 
						||
#include <errno.h>
 | 
						||
#include <netdb.h>
 | 
						||
#include "nsswitch.h"
 | 
						||
 | 
						||
/* Set up NIP to run through the services.  If ALL is zero, use NIP's
 | 
						||
   current location if it's not nil.  Return nonzero if there are no
 | 
						||
   services (left).  */
 | 
						||
static int
 | 
						||
setup (const char *func_name, db_lookup_function lookup_fct,
 | 
						||
       void **fctp, service_user **nip, service_user **startp, int all)
 | 
						||
{
 | 
						||
  int no_more;
 | 
						||
  if (*startp == NULL)
 | 
						||
    {
 | 
						||
      no_more = lookup_fct (nip, func_name, NULL, fctp);
 | 
						||
      *startp = no_more ? (service_user *) -1l : *nip;
 | 
						||
    }
 | 
						||
  else if (*startp == (service_user *) -1l)
 | 
						||
    /* No services at all.  */
 | 
						||
    return 1;
 | 
						||
  else
 | 
						||
    {
 | 
						||
      if (all || !*nip)
 | 
						||
	/* Reset to the beginning of the service list.  */
 | 
						||
	*nip = *startp;
 | 
						||
      /* Look up the first function.  */
 | 
						||
      no_more = __nss_lookup (nip, func_name, NULL, fctp);
 | 
						||
    }
 | 
						||
  return no_more;
 | 
						||
}
 | 
						||
 | 
						||
void
 | 
						||
__nss_setent (const char *func_name, db_lookup_function lookup_fct,
 | 
						||
	      service_user **nip, service_user **startp,
 | 
						||
	      service_user **last_nip, int stayopen, int *stayopen_tmp,
 | 
						||
	      int res)
 | 
						||
{
 | 
						||
  union
 | 
						||
  {
 | 
						||
    setent_function f;
 | 
						||
    void *ptr;
 | 
						||
  } fct;
 | 
						||
  int no_more;
 | 
						||
 | 
						||
  if (res && __res_maybe_init (&_res, 0) == -1)
 | 
						||
    {
 | 
						||
      __set_h_errno (NETDB_INTERNAL);
 | 
						||
      return;
 | 
						||
    }
 | 
						||
 | 
						||
  /* Cycle through the services and run their `setXXent' functions until
 | 
						||
     we find an available service.  */
 | 
						||
  no_more = setup (func_name, lookup_fct, &fct.ptr, nip,
 | 
						||
		   startp, 1);
 | 
						||
  while (! no_more)
 | 
						||
    {
 | 
						||
      int is_last_nip = *nip == *last_nip;
 | 
						||
      enum nss_status status;
 | 
						||
 | 
						||
      if (stayopen_tmp)
 | 
						||
	status = DL_CALL_FCT (fct.f, (*stayopen_tmp));
 | 
						||
      else
 | 
						||
	status = DL_CALL_FCT (fct.f, (0));
 | 
						||
 | 
						||
      no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, status, 0);
 | 
						||
      if (is_last_nip)
 | 
						||
	*last_nip = *nip;
 | 
						||
    }
 | 
						||
 | 
						||
  if (stayopen_tmp)
 | 
						||
    *stayopen_tmp = stayopen;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
void
 | 
						||
__nss_endent (const char *func_name, db_lookup_function lookup_fct,
 | 
						||
	      service_user **nip, service_user **startp,
 | 
						||
	      service_user **last_nip, int res)
 | 
						||
{
 | 
						||
  union
 | 
						||
  {
 | 
						||
    endent_function f;
 | 
						||
    void *ptr;
 | 
						||
  } fct;
 | 
						||
  int no_more;
 | 
						||
 | 
						||
  if (res && __res_maybe_init (&_res, 0) == -1)
 | 
						||
    {
 | 
						||
      __set_h_errno (NETDB_INTERNAL);
 | 
						||
      return;
 | 
						||
    }
 | 
						||
 | 
						||
  /* Cycle through all the services and run their endXXent functions.  */
 | 
						||
  no_more = setup (func_name, lookup_fct, &fct.ptr, nip, startp, 1);
 | 
						||
  while (! no_more)
 | 
						||
    {
 | 
						||
      /* Ignore status, we force check in __NSS_NEXT.  */
 | 
						||
      DL_CALL_FCT (fct.f, ());
 | 
						||
 | 
						||
      if (*nip == *last_nip)
 | 
						||
	/* We have processed all services which were used.  */
 | 
						||
	break;
 | 
						||
 | 
						||
      no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1);
 | 
						||
    }
 | 
						||
  *last_nip = *nip = NULL;
 | 
						||
}
 | 
						||
 | 
						||
 | 
						||
int
 | 
						||
__nss_getent_r (const char *getent_func_name,
 | 
						||
		const char *setent_func_name,
 | 
						||
		db_lookup_function lookup_fct,
 | 
						||
		service_user **nip, service_user **startp,
 | 
						||
		service_user **last_nip, int *stayopen_tmp, int res,
 | 
						||
		void *resbuf, char *buffer, size_t buflen,
 | 
						||
		void **result, int *h_errnop)
 | 
						||
{
 | 
						||
  union
 | 
						||
  {
 | 
						||
    getent_function f;
 | 
						||
    void *ptr;
 | 
						||
  } fct;
 | 
						||
  int no_more;
 | 
						||
  enum nss_status status;
 | 
						||
 | 
						||
  if (res && __res_maybe_init (&_res, 0) == -1)
 | 
						||
    {
 | 
						||
      *h_errnop = NETDB_INTERNAL;
 | 
						||
      *result = NULL;
 | 
						||
      return errno;
 | 
						||
    }
 | 
						||
 | 
						||
  /* Initialize status to return if no more functions are found.  */
 | 
						||
  status = NSS_STATUS_NOTFOUND;
 | 
						||
 | 
						||
  /* Run through available functions, starting with the same function last
 | 
						||
     run.  We will repeat each function as long as it succeeds, and then go
 | 
						||
     on to the next service action.  */
 | 
						||
  no_more = setup (getent_func_name, lookup_fct, &fct.ptr, nip,
 | 
						||
		   startp, 0);
 | 
						||
  while (! no_more)
 | 
						||
    {
 | 
						||
      int is_last_nip = *nip == *last_nip;
 | 
						||
 | 
						||
      status = DL_CALL_FCT (fct.f,
 | 
						||
			    (resbuf, buffer, buflen, &errno, &h_errno));
 | 
						||
 | 
						||
      /* The status is NSS_STATUS_TRYAGAIN and errno is ERANGE the
 | 
						||
	 provided buffer is too small.  In this case we should give
 | 
						||
	 the user the possibility to enlarge the buffer and we should
 | 
						||
	 not simply go on with the next service (even if the TRYAGAIN
 | 
						||
	 action tells us so).  */
 | 
						||
      if (status == NSS_STATUS_TRYAGAIN
 | 
						||
	  && (h_errnop == NULL || *h_errnop == NETDB_INTERNAL)
 | 
						||
	  && errno == ERANGE)
 | 
						||
	break;
 | 
						||
 | 
						||
      do
 | 
						||
	{
 | 
						||
	  no_more = __nss_next2 (nip, getent_func_name, NULL, &fct.ptr,
 | 
						||
				 status, 0);
 | 
						||
 | 
						||
	  if (is_last_nip)
 | 
						||
	    *last_nip = *nip;
 | 
						||
 | 
						||
	  if (! no_more)
 | 
						||
	    {
 | 
						||
	      /* Call the `setXXent' function.  This wasn't done before.  */
 | 
						||
	      union
 | 
						||
	      {
 | 
						||
		setent_function f;
 | 
						||
		void *ptr;
 | 
						||
	      } sfct;
 | 
						||
 | 
						||
	      no_more = __nss_lookup (nip, setent_func_name, NULL, &sfct.ptr);
 | 
						||
 | 
						||
	      if (! no_more)
 | 
						||
	        {
 | 
						||
		  if (stayopen_tmp)
 | 
						||
		    status = DL_CALL_FCT (sfct.f, (*stayopen_tmp));
 | 
						||
		  else
 | 
						||
		    status = DL_CALL_FCT (sfct.f, (0));
 | 
						||
		}
 | 
						||
	      else
 | 
						||
		status = NSS_STATUS_NOTFOUND;
 | 
						||
	    }
 | 
						||
	}
 | 
						||
      while (! no_more && status != NSS_STATUS_SUCCESS);
 | 
						||
    }
 | 
						||
 | 
						||
  *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
 | 
						||
  return (status == NSS_STATUS_SUCCESS ? 0
 | 
						||
	  : status != NSS_STATUS_TRYAGAIN ? ENOENT
 | 
						||
	  /* h_errno functions only set errno if h_errno is NETDB_INTERNAL.  */
 | 
						||
	  : (h_errnop == NULL || *h_errnop == NETDB_INTERNAL) ? errno
 | 
						||
	  : EAGAIN);
 | 
						||
}
 |