(root)/
glibc-2.38/
nss/
nss_action_parse.c
       1  /* Parse a service line from nsswitch.conf.
       2     Copyright (c) 1996-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include <nsswitch.h>
      20  
      21  #include <ctype.h>
      22  #include <string.h>
      23  #include <stdbool.h>
      24  
      25  /* Staging area during parsing.  */
      26  #define DYNARRAY_STRUCT action_list
      27  #define DYNARRAY_ELEMENT struct nss_action
      28  #define DYNARRAY_PREFIX action_list_
      29  #include <malloc/dynarray-skeleton.c>
      30  
      31  /* Skip whitespace in line[].  */
      32  #define SKIP_WS() \
      33    while (line[0] != '\0' && isspace (line[0]))	\
      34      ++line;
      35  
      36  /* Read the source names:
      37          `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
      38     */
      39  static bool
      40  nss_action_parse (const char *line, struct action_list *result)
      41  {
      42    while (1)
      43      {
      44        SKIP_WS ();
      45        if (line[0] == '\0')
      46          /* No more sources specified.  */
      47          return true;
      48  
      49        /* Read <source> identifier.  */
      50        const char *name = line;
      51        while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
      52          ++line;
      53        if (name == line)
      54          return true;
      55  
      56        struct nss_action new_service
      57          = { .module = __nss_module_allocate (name, line - name), };
      58        if (new_service.module == NULL)
      59          {
      60            /* Memory allocation error.  */
      61            action_list_mark_failed (result);
      62            return false;
      63          }
      64        nss_action_set_all (&new_service, NSS_ACTION_CONTINUE);
      65        nss_action_set (&new_service, NSS_STATUS_SUCCESS, NSS_ACTION_RETURN);
      66        nss_action_set (&new_service, NSS_STATUS_RETURN, NSS_ACTION_RETURN);
      67  
      68        SKIP_WS ();
      69  
      70        if (line[0] == '[')
      71          {
      72            /* Read criterions.  */
      73  
      74  	  /* Skip the '['.  */
      75  	  ++line;
      76  	  SKIP_WS ();
      77  
      78            do
      79              {
      80                int not;
      81                enum nss_status status;
      82                lookup_actions action;
      83  
      84                /* Grok ! before name to mean all statuses but that one.  */
      85                not = line[0] == '!';
      86                if (not)
      87                  ++line;
      88  
      89                /* Read status name.  */
      90                name = line;
      91                while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
      92                       && line[0] != ']')
      93                  ++line;
      94  
      95                /* Compare with known statuses.  */
      96                if (line - name == 7)
      97                  {
      98                    if (__strncasecmp (name, "SUCCESS", 7) == 0)
      99                      status = NSS_STATUS_SUCCESS;
     100                    else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
     101                      status = NSS_STATUS_UNAVAIL;
     102                    else
     103                      return false;
     104                  }
     105                else if (line - name == 8)
     106                  {
     107                    if (__strncasecmp (name, "NOTFOUND", 8) == 0)
     108                      status = NSS_STATUS_NOTFOUND;
     109                    else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
     110                      status = NSS_STATUS_TRYAGAIN;
     111                    else
     112                      return false;
     113                  }
     114                else
     115  		return false;
     116  
     117  	      SKIP_WS ();
     118                if (line[0] != '=')
     119                  return false;
     120  
     121  	      /* Skip the '='.  */
     122  	      ++line;
     123  	      SKIP_WS ();
     124                name = line;
     125                while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
     126                       && line[0] != ']')
     127                  ++line;
     128  
     129                if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
     130                  action = NSS_ACTION_RETURN;
     131                else if (line - name == 8
     132                         && __strncasecmp (name, "CONTINUE", 8) == 0)
     133                  action = NSS_ACTION_CONTINUE;
     134                else if (line - name == 5
     135                         && __strncasecmp (name, "MERGE", 5) == 0)
     136                  action = NSS_ACTION_MERGE;
     137                else
     138                  return false;
     139  
     140                if (not)
     141                  {
     142                    /* Save the current action setting for this status,
     143                       set them all to the given action, and reset this one.  */
     144                    const lookup_actions save
     145                      = nss_action_get (&new_service, status);
     146                    nss_action_set_all (&new_service, action);
     147                    nss_action_set (&new_service, status, save);
     148                  }
     149                else
     150                  nss_action_set (&new_service, status, action);
     151  
     152  	      SKIP_WS ();
     153              }
     154            while (line[0] != ']');
     155  
     156            /* Skip the ']'.  */
     157            ++line;
     158          }
     159  
     160        action_list_add (result, new_service);
     161      }
     162  }
     163  
     164  nss_action_list
     165   __nss_action_parse (const char *line)
     166  {
     167    struct action_list list;
     168    action_list_init (&list);
     169    if (nss_action_parse (line, &list))
     170      {
     171        size_t size;
     172        struct nss_action null_service
     173          = { .module = NULL, };
     174  
     175        action_list_add (&list, null_service);
     176        size = action_list_size (&list);
     177        return __nss_action_allocate (action_list_begin (&list), size);
     178      }
     179    else if (action_list_has_failed (&list))
     180      {
     181        /* Memory allocation error.  */
     182        __set_errno (ENOMEM);
     183        return NULL;
     184      }
     185    else
     186      {
     187        /* Parse error.  */
     188        __set_errno (EINVAL);
     189        return NULL;
     190      }
     191  }