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