]>
Commit | Line | Data |
---|---|---|
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 | ||
13 | int 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 | |
67 | static 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 | ||
87 | static 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 | ||
107 | static 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 | ||
135 | typedef int (*parse_token_f)( | |
136 | const char *, | |
137 | int *, | |
138 | int *, | |
139 | uint16_t *, | |
140 | uint16_t *); | |
141 | ||
142 | int 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 | |
212 | int 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 | ||
247 | finalize: | |
248 | return free_and_replace(*s, n); | |
249 | } |