mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-03 20:53:13 +03:00 
			
		
		
		
	The keywords in nsswitch.conf are ASCII-only, but some locales map ASCII characters to non-ASCII characters in case conversion.
		
			
				
	
	
		
			203 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			203 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Parse a service line from nsswitch.conf.
 | 
						|
   Copyright (c) 1996-2025 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
 | 
						|
   <https://www.gnu.org/licenses/>.  */
 | 
						|
 | 
						|
#include <nsswitch.h>
 | 
						|
 | 
						|
#include <ctype.h>
 | 
						|
#include <string.h>
 | 
						|
#include <stdbool.h>
 | 
						|
 | 
						|
/* Staging area during parsing.  */
 | 
						|
#define DYNARRAY_STRUCT action_list
 | 
						|
#define DYNARRAY_ELEMENT struct nss_action
 | 
						|
#define DYNARRAY_PREFIX action_list_
 | 
						|
#include <malloc/dynarray-skeleton.c>
 | 
						|
 | 
						|
/* Skip whitespace in line[].  */
 | 
						|
#define SKIP_WS() \
 | 
						|
  while (line[0] != '\0' && isspace (line[0]))	\
 | 
						|
    ++line;
 | 
						|
 | 
						|
/* Read the source names:
 | 
						|
        `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
 | 
						|
   */
 | 
						|
static bool
 | 
						|
nss_action_parse (const char *line, struct action_list *result)
 | 
						|
{
 | 
						|
  while (1)
 | 
						|
    {
 | 
						|
      SKIP_WS ();
 | 
						|
      if (line[0] == '\0')
 | 
						|
        /* No more sources specified.  */
 | 
						|
        return true;
 | 
						|
 | 
						|
      /* Read <source> identifier.  */
 | 
						|
      const char *name = line;
 | 
						|
      while (line[0] != '\0' && !__isspace_l (line[0], _nl_C_locobj_ptr)
 | 
						|
	     && line[0] != '[')
 | 
						|
        ++line;
 | 
						|
      if (name == line)
 | 
						|
        return true;
 | 
						|
 | 
						|
      struct nss_action new_service
 | 
						|
        = { .module = __nss_module_allocate (name, line - name), };
 | 
						|
      if (new_service.module == NULL)
 | 
						|
        {
 | 
						|
          /* Memory allocation error.  */
 | 
						|
          action_list_mark_failed (result);
 | 
						|
          return false;
 | 
						|
        }
 | 
						|
      nss_action_set_all (&new_service, NSS_ACTION_CONTINUE);
 | 
						|
      nss_action_set (&new_service, NSS_STATUS_SUCCESS, NSS_ACTION_RETURN);
 | 
						|
      nss_action_set (&new_service, NSS_STATUS_RETURN, NSS_ACTION_RETURN);
 | 
						|
 | 
						|
      SKIP_WS ();
 | 
						|
 | 
						|
      if (line[0] == '[')
 | 
						|
        {
 | 
						|
          /* Read criterions.  */
 | 
						|
 | 
						|
	  /* Skip the '['.  */
 | 
						|
	  ++line;
 | 
						|
	  SKIP_WS ();
 | 
						|
 | 
						|
          do
 | 
						|
            {
 | 
						|
              int not;
 | 
						|
              enum nss_status status;
 | 
						|
              lookup_actions action;
 | 
						|
 | 
						|
              /* Grok ! before name to mean all statuses but that one.  */
 | 
						|
              not = line[0] == '!';
 | 
						|
              if (not)
 | 
						|
                ++line;
 | 
						|
 | 
						|
              /* Read status name.  */
 | 
						|
              name = line;
 | 
						|
              while (line[0] != '\0' && !__isspace_l (line[0], _nl_C_locobj_ptr)
 | 
						|
		     && line[0] != '=' && line[0] != ']')
 | 
						|
                ++line;
 | 
						|
 | 
						|
              /* Compare with known statuses.  */
 | 
						|
              if (line - name == 7)
 | 
						|
                {
 | 
						|
                  if (__strncasecmp_l (name, "SUCCESS", 7,
 | 
						|
				       _nl_C_locobj_ptr) == 0)
 | 
						|
                    status = NSS_STATUS_SUCCESS;
 | 
						|
                  else if (__strncasecmp_l (name, "UNAVAIL", 7,
 | 
						|
					    _nl_C_locobj_ptr) == 0)
 | 
						|
                    status = NSS_STATUS_UNAVAIL;
 | 
						|
                  else
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
              else if (line - name == 8)
 | 
						|
                {
 | 
						|
                  if (__strncasecmp_l (name, "NOTFOUND", 8,
 | 
						|
				       _nl_C_locobj_ptr) == 0)
 | 
						|
                    status = NSS_STATUS_NOTFOUND;
 | 
						|
                  else if (__strncasecmp_l (name, "TRYAGAIN", 8,
 | 
						|
					    _nl_C_locobj_ptr) == 0)
 | 
						|
                    status = NSS_STATUS_TRYAGAIN;
 | 
						|
                  else
 | 
						|
                    return false;
 | 
						|
                }
 | 
						|
              else
 | 
						|
		return false;
 | 
						|
 | 
						|
	      SKIP_WS ();
 | 
						|
              if (line[0] != '=')
 | 
						|
                return false;
 | 
						|
 | 
						|
	      /* Skip the '='.  */
 | 
						|
	      ++line;
 | 
						|
	      SKIP_WS ();
 | 
						|
              name = line;
 | 
						|
              while (line[0] != '\0' && !__isspace_l (line[0], _nl_C_locobj_ptr)
 | 
						|
		     && line[0] != '=' && line[0] != ']')
 | 
						|
                ++line;
 | 
						|
 | 
						|
              if (line - name == 6
 | 
						|
		  && __strncasecmp_l (name, "RETURN", 6, _nl_C_locobj_ptr) == 0)
 | 
						|
                action = NSS_ACTION_RETURN;
 | 
						|
              else if (line - name == 8
 | 
						|
                       && __strncasecmp_l (name, "CONTINUE", 8,
 | 
						|
					   _nl_C_locobj_ptr) == 0)
 | 
						|
                action = NSS_ACTION_CONTINUE;
 | 
						|
              else if (line - name == 5
 | 
						|
                       && __strncasecmp_l (name, "MERGE", 5,
 | 
						|
					   _nl_C_locobj_ptr) == 0)
 | 
						|
                action = NSS_ACTION_MERGE;
 | 
						|
              else
 | 
						|
                return false;
 | 
						|
 | 
						|
              if (not)
 | 
						|
                {
 | 
						|
                  /* Save the current action setting for this status,
 | 
						|
                     set them all to the given action, and reset this one.  */
 | 
						|
                  const lookup_actions save
 | 
						|
                    = nss_action_get (&new_service, status);
 | 
						|
                  nss_action_set_all (&new_service, action);
 | 
						|
                  nss_action_set (&new_service, status, save);
 | 
						|
                }
 | 
						|
              else
 | 
						|
                nss_action_set (&new_service, status, action);
 | 
						|
 | 
						|
	      SKIP_WS ();
 | 
						|
            }
 | 
						|
          while (line[0] != ']');
 | 
						|
 | 
						|
          /* Skip the ']'.  */
 | 
						|
          ++line;
 | 
						|
        }
 | 
						|
 | 
						|
      action_list_add (result, new_service);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
nss_action_list
 | 
						|
 __nss_action_parse (const char *line)
 | 
						|
{
 | 
						|
  struct action_list list;
 | 
						|
  action_list_init (&list);
 | 
						|
  if (nss_action_parse (line, &list))
 | 
						|
    {
 | 
						|
      nss_action_list retval;
 | 
						|
      size_t size;
 | 
						|
      struct nss_action null_service
 | 
						|
        = { .module = NULL, };
 | 
						|
 | 
						|
      action_list_add (&list, null_service);
 | 
						|
      size = action_list_size (&list);
 | 
						|
      retval = __nss_action_allocate (action_list_begin (&list), size);
 | 
						|
      action_list_free (&list);
 | 
						|
      return retval;
 | 
						|
    }
 | 
						|
  else if (action_list_has_failed (&list))
 | 
						|
    {
 | 
						|
      /* Memory allocation error.  */
 | 
						|
      __set_errno (ENOMEM);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
  else
 | 
						|
    {
 | 
						|
      /* Parse error.  */
 | 
						|
      __set_errno (EINVAL);
 | 
						|
      return NULL;
 | 
						|
    }
 | 
						|
}
 |