1/* Parse a service line from nsswitch.conf.
2 Copyright (c) 1996-2022 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 */
39static bool
40nss_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, name_length: line - name), };
58 if (new_service.module == NULL)
59 {
60 /* Memory allocation error. */
61 action_list_mark_failed (list: result);
62 return false;
63 }
64 nss_action_set_all (action: &new_service, actions: NSS_ACTION_CONTINUE);
65 nss_action_set (action: &new_service, status: NSS_STATUS_SUCCESS, actions: NSS_ACTION_RETURN);
66 nss_action_set (action: &new_service, status: NSS_STATUS_RETURN, actions: 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 (s1: name, s2: "SUCCESS", n: 7) == 0)
99 status = NSS_STATUS_SUCCESS;
100 else if (__strncasecmp (s1: name, s2: "UNAVAIL", n: 7) == 0)
101 status = NSS_STATUS_UNAVAIL;
102 else
103 return false;
104 }
105 else if (line - name == 8)
106 {
107 if (__strncasecmp (s1: name, s2: "NOTFOUND", n: 8) == 0)
108 status = NSS_STATUS_NOTFOUND;
109 else if (__strncasecmp (s1: name, s2: "TRYAGAIN", n: 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 (s1: name, s2: "RETURN", n: 6) == 0)
130 action = NSS_ACTION_RETURN;
131 else if (line - name == 8
132 && __strncasecmp (s1: name, s2: "CONTINUE", n: 8) == 0)
133 action = NSS_ACTION_CONTINUE;
134 else if (line - name == 5
135 && __strncasecmp (s1: name, s2: "MERGE", n: 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 (action: &new_service, status);
146 nss_action_set_all (action: &new_service, actions: action);
147 nss_action_set (action: &new_service, status, actions: save);
148 }
149 else
150 nss_action_set (action: &new_service, status, actions: action);
151
152 SKIP_WS ();
153 }
154 while (line[0] != ']');
155
156 /* Skip the ']'. */
157 ++line;
158 }
159
160 action_list_add (list: result, item: new_service);
161 }
162}
163
164nss_action_list
165 __nss_action_parse (const char *line)
166{
167 struct action_list list;
168 action_list_init (list: &list);
169 if (nss_action_parse (line, result: &list))
170 {
171 size_t size;
172 struct nss_action null_service
173 = { .module = NULL, };
174
175 action_list_add (list: &list, item: null_service);
176 size = action_list_size (list: &list);
177 return __nss_action_allocate (actions: action_list_begin (list: &list), count: size);
178 }
179 else if (action_list_has_failed (list: &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}
192

source code of glibc/nss/nss_action_parse.c