mirror of
https://sourceware.org/git/glibc.git
synced 2024-11-14 09:01:07 +00:00
fd5b9b4458
nss_action manages a set of lists of actions; these are the portions of the lines in nsswitch.conf to the right of the colons, like "dns [!UNAVAIL=return] files". Each permutation of actions and conditionals is cached for reuse, which limits memory growth, and refers to the static list of modules managed by nss_modules. Reviewed-by: Siddhesh Poyarekar <siddhesh@sourceware.org>
198 lines
5.8 KiB
C
198 lines
5.8 KiB
C
/* Parse a service line from nsswitch.conf.
|
|
Copyright (c) 1996-2020 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 "nss_action.h"
|
|
#include "nss_module.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 (line[0]) && 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 (line[0]) && line[0] != '='
|
|
&& line[0] != ']')
|
|
++line;
|
|
|
|
/* Compare with known statuses. */
|
|
if (line - name == 7)
|
|
{
|
|
if (__strncasecmp (name, "SUCCESS", 7) == 0)
|
|
status = NSS_STATUS_SUCCESS;
|
|
else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
|
|
status = NSS_STATUS_UNAVAIL;
|
|
else
|
|
return false;
|
|
}
|
|
else if (line - name == 8)
|
|
{
|
|
if (__strncasecmp (name, "NOTFOUND", 8) == 0)
|
|
status = NSS_STATUS_NOTFOUND;
|
|
else if (__strncasecmp (name, "TRYAGAIN", 8) == 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 (line[0]) && line[0] != '='
|
|
&& line[0] != ']')
|
|
++line;
|
|
|
|
if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
|
|
action = NSS_ACTION_RETURN;
|
|
else if (line - name == 8
|
|
&& __strncasecmp (name, "CONTINUE", 8) == 0)
|
|
action = NSS_ACTION_CONTINUE;
|
|
else if (line - name == 5
|
|
&& __strncasecmp (name, "MERGE", 5) == 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))
|
|
{
|
|
size_t size = action_list_size (&list);
|
|
nss_action_list result
|
|
= malloc (sizeof (*result) * (size + 1));
|
|
if (result == NULL)
|
|
{
|
|
action_list_free (&list);
|
|
return NULL;
|
|
}
|
|
memcpy (result, action_list_begin (&list), sizeof (*result) * size);
|
|
/* Sentinel. */
|
|
result[size].module = NULL;
|
|
return result;
|
|
}
|
|
else if (action_list_has_failed (&list))
|
|
{
|
|
/* Memory allocation error. */
|
|
__set_errno (ENOMEM);
|
|
return NULL;
|
|
}
|
|
else
|
|
{
|
|
/* Parse error. */
|
|
__set_errno (EINVAL);
|
|
return NULL;
|
|
}
|
|
}
|