| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202 |
- /* Parse a service line from nsswitch.conf.
- Copyright (c) 1996-2026 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;
- }
- }
|