]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/parse-helpers.c
parse-helpers: add new PATH_CHECK_NON_API_VFS flag
[thirdparty/systemd.git] / src / shared / parse-helpers.c
CommitLineData
c3eaba2d
ZJS
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3fb72d63
ZJS
3#include "af-list.h"
4#include "extract-word.h"
5#include "ip-protocol-list.h"
c3eaba2d 6#include "log.h"
0d133284 7#include "mountpoint-util.h"
c3eaba2d 8#include "parse-helpers.h"
3fb72d63 9#include "parse-util.h"
c3eaba2d
ZJS
10#include "path-util.h"
11#include "utf8.h"
12
13int path_simplify_and_warn(
14 char *path,
0d133284 15 PathSimplifyWarnFlags flags,
c3eaba2d
ZJS
16 const char *unit,
17 const char *filename,
18 unsigned line,
19 const char *lvalue) {
20
0d133284 21 bool fatal = flags & PATH_CHECK_FATAL;
c3eaba2d 22
0d133284
LP
23 assert(path);
24 assert(!FLAGS_SET(flags, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE));
25 assert(lvalue);
c3eaba2d
ZJS
26
27 if (!utf8_is_valid(path))
28 return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path);
29
0d133284 30 if (flags & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) {
c3eaba2d
ZJS
31 bool absolute;
32
33 absolute = path_is_absolute(path);
34
0d133284 35 if (!absolute && (flags & PATH_CHECK_ABSOLUTE))
c3eaba2d
ZJS
36 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
37 "%s= path is not absolute%s: %s",
38 lvalue, fatal ? "" : ", ignoring", path);
39
0d133284 40 if (absolute && (flags & PATH_CHECK_RELATIVE))
c3eaba2d
ZJS
41 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
42 "%s= path is absolute%s: %s",
43 lvalue, fatal ? "" : ", ignoring", path);
44 }
45
0d133284 46 path_simplify_full(path, flags & PATH_KEEP_TRAILING_SLASH ? PATH_SIMPLIFY_KEEP_TRAILING_SLASH : 0);
c3eaba2d
ZJS
47
48 if (!path_is_valid(path))
49 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
50 "%s= path has invalid length (%zu bytes)%s.",
51 lvalue, strlen(path), fatal ? "" : ", ignoring");
52
53 if (!path_is_normalized(path))
54 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
55 "%s= path is not normalized%s: %s",
56 lvalue, fatal ? "" : ", ignoring", path);
57
0d133284
LP
58 if (FLAGS_SET(flags, PATH_CHECK_NON_API_VFS) && path_below_api_vfs(path))
59 return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL),
60 "%s= path is below API VFS%s: %s",
61 lvalue, fatal ? ", refusing" : ", ignoring",
62 path);
63
c3eaba2d
ZJS
64 return 0;
65}
3fb72d63
ZJS
66
67static int parse_af_token(
68 const char *token,
69 int *family,
70 int *ip_protocol,
71 uint16_t *nr_ports,
72 uint16_t *port_min) {
73
74 int af;
75
76 assert(token);
77 assert(family);
78
79 af = af_from_ipv4_ipv6(token);
80 if (af == AF_UNSPEC)
81 return -EINVAL;
82
83 *family = af;
84 return 0;
85}
86
87static int parse_ip_protocol_token(
88 const char *token,
89 int *family,
90 int *ip_protocol,
91 uint16_t *nr_ports,
92 uint16_t *port_min) {
93
94 int proto;
95
96 assert(token);
97 assert(ip_protocol);
98
99 proto = ip_protocol_from_tcp_udp(token);
100 if (proto < 0)
101 return -EINVAL;
102
103 *ip_protocol = proto;
104 return 0;
105}
106
107static int parse_ip_ports_token(
108 const char *token,
109 int *family,
110 int *ip_protocol,
111 uint16_t *nr_ports,
112 uint16_t *port_min) {
113
dcfac3a3 114 int r;
115
3fb72d63
ZJS
116 assert(token);
117 assert(nr_ports);
118 assert(port_min);
119
120 if (streq(token, "any"))
121 *nr_ports = *port_min = 0;
122 else {
123 uint16_t mn = 0, mx = 0;
dcfac3a3 124 r = parse_ip_port_range(token, &mn, &mx, /* allow_zero = */ true);
3fb72d63
ZJS
125 if (r < 0)
126 return r;
127
128 *nr_ports = mx - mn + 1;
129 *port_min = mn;
130 }
131
132 return 0;
133}
134
135typedef int (*parse_token_f)(
136 const char *,
137 int *,
138 int *,
139 uint16_t *,
140 uint16_t *);
141
142int parse_socket_bind_item(
143 const char *str,
144 int *address_family,
145 int *ip_protocol,
146 uint16_t *nr_ports,
147 uint16_t *port_min) {
148
149 /* Order of token parsers is important. */
150 const parse_token_f parsers[] = {
151 &parse_af_token,
152 &parse_ip_protocol_token,
153 &parse_ip_ports_token,
154 };
155 parse_token_f const *parser_ptr = parsers;
156 int af = AF_UNSPEC, proto = 0, r;
157 uint16_t nr = 0, mn = 0;
99534007 158 const char *p = ASSERT_PTR(str);
3fb72d63 159
3fb72d63
ZJS
160 assert(address_family);
161 assert(ip_protocol);
162 assert(nr_ports);
163 assert(port_min);
164
165 if (isempty(p))
166 return -EINVAL;
167
168 for (;;) {
169 _cleanup_free_ char *token = NULL;
170
171 r = extract_first_word(&p, &token, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
172 if (r == 0)
173 break;
174 if (r < 0)
175 return r;
176
177 if (isempty(token))
178 return -EINVAL;
179
180 while (parser_ptr != parsers + ELEMENTSOF(parsers)) {
181 r = (*parser_ptr)(token, &af, &proto, &nr, &mn);
182 if (r == -ENOMEM)
183 return r;
184
185 ++parser_ptr;
186 /* Continue to next token if parsing succeeded,
187 * otherwise apply next parser to the same token.
188 */
189 if (r >= 0)
190 break;
191 }
192 if (parser_ptr == parsers + ELEMENTSOF(parsers))
193 break;
194 }
195
196 /* Failed to parse a token. */
197 if (r < 0)
198 return r;
199
200 /* Parsers applied successfully, but end of the string not reached. */
201 if (p)
202 return -EINVAL;
203
204 *address_family = af;
205 *ip_protocol = proto;
206 *nr_ports = nr;
207 *port_min = mn;
dcfac3a3 208
3fb72d63
ZJS
209 return 0;
210}
d7085bcc
FS
211
212int config_parse_path_or_ignore(
213 const char *unit,
214 const char *filename,
215 unsigned line,
216 const char *section,
217 unsigned section_line,
218 const char *lvalue,
219 int ltype,
220 const char *rvalue,
221 void *data,
222 void *userdata) {
223
224 _cleanup_free_ char *n = NULL;
225 bool fatal = ltype;
226 char **s = ASSERT_PTR(data);
227 int r;
228
229 assert(filename);
230 assert(lvalue);
231 assert(rvalue);
232
233 if (isempty(rvalue))
234 goto finalize;
235
236 n = strdup(rvalue);
237 if (!n)
238 return log_oom();
239
240 if (streq(n, "-"))
241 goto finalize;
242
243 r = path_simplify_and_warn(n, PATH_CHECK_ABSOLUTE | (fatal ? PATH_CHECK_FATAL : 0), unit, filename, line, lvalue);
244 if (r < 0)
245 return fatal ? -ENOEXEC : 0;
246
247finalize:
248 return free_and_replace(*s, n);
249}