]> git.ipfire.org Git - thirdparty/glibc.git/blob - nss/nss_action_parse.c
1a7643a88423039b5a2695ee8b6354ad7afe83e8
[thirdparty/glibc.git] / nss / nss_action_parse.c
1 /* Parse a service line from nsswitch.conf.
2 Copyright (c) 1996-2020 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 "nss_action.h"
20 #include "nss_module.h"
21
22 #include <ctype.h>
23 #include <string.h>
24 #include <stdbool.h>
25
26 /* Staging area during parsing. */
27 #define DYNARRAY_STRUCT action_list
28 #define DYNARRAY_ELEMENT struct nss_action
29 #define DYNARRAY_PREFIX action_list_
30 #include <malloc/dynarray-skeleton.c>
31
32 /* Skip whitespace in line[]. */
33 #define SKIP_WS() \
34 while (line[0] != '\0' && isspace (line[0])) \
35 ++line;
36
37 /* Read the source names:
38 `( <source> ( "[" "!"? (<status> "=" <action> )+ "]" )? )*'
39 */
40 static bool
41 nss_action_parse (const char *line, struct action_list *result)
42 {
43 while (1)
44 {
45 SKIP_WS ();
46 if (line[0] == '\0')
47 /* No more sources specified. */
48 return true;
49
50 /* Read <source> identifier. */
51 const char *name = line;
52 while (line[0] != '\0' && !isspace (line[0]) && line[0] != '[')
53 ++line;
54 if (name == line)
55 return true;
56
57 struct nss_action new_service
58 = { .module = __nss_module_allocate (name, line - name), };
59 if (new_service.module == NULL)
60 {
61 /* Memory allocation error. */
62 action_list_mark_failed (result);
63 return false;
64 }
65 nss_action_set_all (&new_service, NSS_ACTION_CONTINUE);
66 nss_action_set (&new_service, NSS_STATUS_SUCCESS, NSS_ACTION_RETURN);
67 nss_action_set (&new_service, NSS_STATUS_RETURN, NSS_ACTION_RETURN);
68
69 SKIP_WS ();
70
71 if (line[0] == '[')
72 {
73 /* Read criterions. */
74
75 /* Skip the '['. */
76 ++line;
77 SKIP_WS ();
78
79 do
80 {
81 int not;
82 enum nss_status status;
83 lookup_actions action;
84
85 /* Grok ! before name to mean all statuses but that one. */
86 not = line[0] == '!';
87 if (not)
88 ++line;
89
90 /* Read status name. */
91 name = line;
92 while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
93 && line[0] != ']')
94 ++line;
95
96 /* Compare with known statuses. */
97 if (line - name == 7)
98 {
99 if (__strncasecmp (name, "SUCCESS", 7) == 0)
100 status = NSS_STATUS_SUCCESS;
101 else if (__strncasecmp (name, "UNAVAIL", 7) == 0)
102 status = NSS_STATUS_UNAVAIL;
103 else
104 return false;
105 }
106 else if (line - name == 8)
107 {
108 if (__strncasecmp (name, "NOTFOUND", 8) == 0)
109 status = NSS_STATUS_NOTFOUND;
110 else if (__strncasecmp (name, "TRYAGAIN", 8) == 0)
111 status = NSS_STATUS_TRYAGAIN;
112 else
113 return false;
114 }
115 else
116 return false;
117
118 SKIP_WS ();
119 if (line[0] != '=')
120 return false;
121
122 /* Skip the '='. */
123 ++line;
124 SKIP_WS ();
125 name = line;
126 while (line[0] != '\0' && !isspace (line[0]) && line[0] != '='
127 && line[0] != ']')
128 ++line;
129
130 if (line - name == 6 && __strncasecmp (name, "RETURN", 6) == 0)
131 action = NSS_ACTION_RETURN;
132 else if (line - name == 8
133 && __strncasecmp (name, "CONTINUE", 8) == 0)
134 action = NSS_ACTION_CONTINUE;
135 else if (line - name == 5
136 && __strncasecmp (name, "MERGE", 5) == 0)
137 action = NSS_ACTION_MERGE;
138 else
139 return false;
140
141 if (not)
142 {
143 /* Save the current action setting for this status,
144 set them all to the given action, and reset this one. */
145 const lookup_actions save
146 = nss_action_get (&new_service, status);
147 nss_action_set_all (&new_service, action);
148 nss_action_set (&new_service, status, save);
149 }
150 else
151 nss_action_set (&new_service, status, action);
152
153 SKIP_WS ();
154 }
155 while (line[0] != ']');
156
157 /* Skip the ']'. */
158 ++line;
159 }
160
161 action_list_add (result, new_service);
162 }
163 }
164
165 nss_action_list
166 __nss_action_parse (const char *line)
167 {
168 struct action_list list;
169 action_list_init (&list);
170 if (nss_action_parse (line, &list))
171 {
172 size_t size = action_list_size (&list);
173 nss_action_list result
174 = malloc (sizeof (*result) * (size + 1));
175 if (result == NULL)
176 {
177 action_list_free (&list);
178 return NULL;
179 }
180 memcpy (result, action_list_begin (&list), sizeof (*result) * size);
181 /* Sentinel. */
182 result[size].module = NULL;
183 return result;
184 }
185 else if (action_list_has_failed (&list))
186 {
187 /* Memory allocation error. */
188 __set_errno (ENOMEM);
189 return NULL;
190 }
191 else
192 {
193 /* Parse error. */
194 __set_errno (EINVAL);
195 return NULL;
196 }
197 }