]>
Commit | Line | Data |
---|---|---|
cca2da15 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
7e19cc54 | 2 | |
6553db60 | 3 | #include <fnmatch.h> |
69a283c5 DDM |
4 | |
5 | #include "sd-device.h" | |
7e19cc54 | 6 | |
b78d73fa | 7 | #include "alloc-util.h" |
7e19cc54 YW |
8 | #include "condition.h" |
9 | #include "env-util.h" | |
69a283c5 | 10 | #include "extract-word.h" |
7e19cc54 YW |
11 | #include "log.h" |
12 | #include "net-condition.h" | |
b5cc5591 | 13 | #include "netif-util.h" |
69a283c5 | 14 | #include "set.h" |
7e19cc54 | 15 | #include "socket-util.h" |
69a283c5 | 16 | #include "string-util.h" |
7e19cc54 | 17 | #include "strv.h" |
abad436d | 18 | #include "wifi-util.h" |
7e19cc54 | 19 | |
5722fb89 YW |
20 | void net_match_clear(NetMatch *match) { |
21 | if (!match) | |
22 | return; | |
23 | ||
52135071 YW |
24 | match->hw_addr = set_free(match->hw_addr); |
25 | match->permanent_hw_addr = set_free(match->permanent_hw_addr); | |
5722fb89 YW |
26 | match->path = strv_free(match->path); |
27 | match->driver = strv_free(match->driver); | |
28 | match->iftype = strv_free(match->iftype); | |
65022cd7 | 29 | match->kind = strv_free(match->kind); |
5722fb89 YW |
30 | match->ifname = strv_free(match->ifname); |
31 | match->property = strv_free(match->property); | |
77f75f4f | 32 | match->wlan_iftype = strv_free(match->wlan_iftype); |
5722fb89 | 33 | match->ssid = strv_free(match->ssid); |
c6df73ca | 34 | match->bssid = set_free(match->bssid); |
5722fb89 YW |
35 | } |
36 | ||
37 | bool net_match_is_empty(const NetMatch *match) { | |
38 | assert(match); | |
39 | ||
40 | return | |
52135071 YW |
41 | set_isempty(match->hw_addr) && |
42 | set_isempty(match->permanent_hw_addr) && | |
5722fb89 YW |
43 | strv_isempty(match->path) && |
44 | strv_isempty(match->driver) && | |
45 | strv_isempty(match->iftype) && | |
65022cd7 | 46 | strv_isempty(match->kind) && |
5722fb89 YW |
47 | strv_isempty(match->ifname) && |
48 | strv_isempty(match->property) && | |
77f75f4f | 49 | strv_isempty(match->wlan_iftype) && |
5722fb89 YW |
50 | strv_isempty(match->ssid) && |
51 | set_isempty(match->bssid); | |
52 | } | |
53 | ||
7e19cc54 | 54 | static bool net_condition_test_strv(char * const *patterns, const char *string) { |
7e19cc54 YW |
55 | bool match = false, has_positive_rule = false; |
56 | ||
57 | if (strv_isempty(patterns)) | |
58 | return true; | |
59 | ||
60 | STRV_FOREACH(p, patterns) { | |
61 | const char *q = *p; | |
62 | bool invert; | |
63 | ||
64 | invert = *q == '!'; | |
65 | q += invert; | |
66 | ||
67 | if (!invert) | |
68 | has_positive_rule = true; | |
69 | ||
70 | if (string && fnmatch(q, string, 0) == 0) { | |
71 | if (invert) | |
72 | return false; | |
73 | else | |
74 | match = true; | |
75 | } | |
76 | } | |
77 | ||
78 | return has_positive_rule ? match : true; | |
79 | } | |
80 | ||
81 | static bool net_condition_test_ifname(char * const *patterns, const char *ifname, char * const *alternative_names) { | |
82 | if (net_condition_test_strv(patterns, ifname)) | |
83 | return true; | |
84 | ||
7e19cc54 YW |
85 | STRV_FOREACH(p, alternative_names) |
86 | if (net_condition_test_strv(patterns, *p)) | |
87 | return true; | |
88 | ||
89 | return false; | |
90 | } | |
91 | ||
92 | static int net_condition_test_property(char * const *match_property, sd_device *device) { | |
7e19cc54 YW |
93 | if (strv_isempty(match_property)) |
94 | return true; | |
95 | ||
96 | STRV_FOREACH(p, match_property) { | |
97 | _cleanup_free_ char *key = NULL; | |
98 | const char *val, *dev_val; | |
99 | bool invert, v; | |
100 | ||
101 | invert = **p == '!'; | |
102 | ||
103 | val = strchr(*p + invert, '='); | |
104 | if (!val) | |
105 | return -EINVAL; | |
106 | ||
107 | key = strndup(*p + invert, val - *p - invert); | |
108 | if (!key) | |
109 | return -ENOMEM; | |
110 | ||
111 | val++; | |
112 | ||
113 | v = device && | |
114 | sd_device_get_property_value(device, key, &dev_val) >= 0 && | |
115 | fnmatch(val, dev_val, 0) == 0; | |
116 | ||
117 | if (invert ? v : !v) | |
118 | return false; | |
119 | } | |
120 | ||
121 | return true; | |
122 | } | |
123 | ||
1a3caa49 | 124 | int net_match_config( |
5722fb89 | 125 | const NetMatch *match, |
7e19cc54 | 126 | sd_device *device, |
52135071 YW |
127 | const struct hw_addr_data *hw_addr, |
128 | const struct hw_addr_data *permanent_hw_addr, | |
5722fb89 YW |
129 | const char *driver, |
130 | unsigned short iftype, | |
65022cd7 | 131 | const char *kind, |
5722fb89 | 132 | const char *ifname, |
7e19cc54 | 133 | char * const *alternative_names, |
77f75f4f | 134 | enum nl80211_iftype wlan_iftype, |
5722fb89 YW |
135 | const char *ssid, |
136 | const struct ether_addr *bssid) { | |
137 | ||
c2b2df60 | 138 | _cleanup_free_ char *iftype_str = NULL; |
5722fb89 | 139 | const char *path = NULL; |
7e19cc54 | 140 | |
5722fb89 | 141 | assert(match); |
7e19cc54 | 142 | |
613701a4 YW |
143 | if (net_get_type_string(device, iftype, &iftype_str) == -ENOMEM) |
144 | return -ENOMEM; | |
7e19cc54 | 145 | |
613701a4 | 146 | if (device) |
5722fb89 | 147 | (void) sd_device_get_property_value(device, "ID_PATH", &path); |
7e19cc54 | 148 | |
52135071 | 149 | if (match->hw_addr && (!hw_addr || !set_contains(match->hw_addr, hw_addr))) |
7e19cc54 YW |
150 | return false; |
151 | ||
52135071 YW |
152 | if (match->permanent_hw_addr && |
153 | (!permanent_hw_addr || | |
154 | !set_contains(match->permanent_hw_addr, permanent_hw_addr))) | |
7e19cc54 YW |
155 | return false; |
156 | ||
5722fb89 | 157 | if (!net_condition_test_strv(match->path, path)) |
7e19cc54 YW |
158 | return false; |
159 | ||
5722fb89 | 160 | if (!net_condition_test_strv(match->driver, driver)) |
7e19cc54 YW |
161 | return false; |
162 | ||
5722fb89 | 163 | if (!net_condition_test_strv(match->iftype, iftype_str)) |
7e19cc54 YW |
164 | return false; |
165 | ||
65022cd7 YW |
166 | if (!net_condition_test_strv(match->kind, kind)) |
167 | return false; | |
168 | ||
5722fb89 | 169 | if (!net_condition_test_ifname(match->ifname, ifname, alternative_names)) |
7e19cc54 YW |
170 | return false; |
171 | ||
5722fb89 | 172 | if (!net_condition_test_property(match->property, device)) |
7e19cc54 YW |
173 | return false; |
174 | ||
77f75f4f | 175 | if (!net_condition_test_strv(match->wlan_iftype, nl80211_iftype_to_string(wlan_iftype))) |
7e19cc54 YW |
176 | return false; |
177 | ||
5722fb89 | 178 | if (!net_condition_test_strv(match->ssid, ssid)) |
7e19cc54 YW |
179 | return false; |
180 | ||
5722fb89 | 181 | if (match->bssid && (!bssid || !set_contains(match->bssid, bssid))) |
7e19cc54 YW |
182 | return false; |
183 | ||
184 | return true; | |
185 | } | |
186 | ||
187 | int config_parse_net_condition( | |
188 | const char *unit, | |
189 | const char *filename, | |
190 | unsigned line, | |
191 | const char *section, | |
192 | unsigned section_line, | |
193 | const char *lvalue, | |
194 | int ltype, | |
195 | const char *rvalue, | |
196 | void *data, | |
197 | void *userdata) { | |
198 | ||
199 | ConditionType cond = ltype; | |
200 | Condition **list = data, *c; | |
201 | bool negate; | |
202 | ||
203 | assert(filename); | |
204 | assert(lvalue); | |
205 | assert(rvalue); | |
206 | assert(data); | |
207 | ||
208 | if (isempty(rvalue)) { | |
209 | *list = condition_free_list_type(*list, cond); | |
210 | return 0; | |
211 | } | |
212 | ||
213 | negate = rvalue[0] == '!'; | |
214 | if (negate) | |
215 | rvalue++; | |
216 | ||
217 | c = condition_new(cond, rvalue, false, negate); | |
218 | if (!c) | |
219 | return log_oom(); | |
220 | ||
221 | /* Drop previous assignment. */ | |
222 | *list = condition_free_list_type(*list, cond); | |
223 | ||
224 | LIST_PREPEND(conditions, *list, c); | |
225 | return 0; | |
226 | } | |
227 | ||
228 | int config_parse_match_strv( | |
229 | const char *unit, | |
230 | const char *filename, | |
231 | unsigned line, | |
232 | const char *section, | |
233 | unsigned section_line, | |
234 | const char *lvalue, | |
235 | int ltype, | |
236 | const char *rvalue, | |
237 | void *data, | |
238 | void *userdata) { | |
239 | ||
99534007 DT |
240 | const char *p = ASSERT_PTR(rvalue); |
241 | char ***sv = ASSERT_PTR(data); | |
7e19cc54 YW |
242 | bool invert; |
243 | int r; | |
244 | ||
245 | assert(filename); | |
246 | assert(lvalue); | |
7e19cc54 YW |
247 | |
248 | if (isempty(rvalue)) { | |
249 | *sv = strv_free(*sv); | |
250 | return 0; | |
251 | } | |
252 | ||
253 | invert = *p == '!'; | |
254 | p += invert; | |
255 | ||
256 | for (;;) { | |
257 | _cleanup_free_ char *word = NULL, *k = NULL; | |
258 | ||
259 | r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE); | |
260 | if (r == 0) | |
261 | return 0; | |
262 | if (r == -ENOMEM) | |
263 | return log_oom(); | |
264 | if (r < 0) { | |
265 | log_syntax(unit, LOG_WARNING, filename, line, r, | |
266 | "Invalid syntax, ignoring: %s", rvalue); | |
267 | return 0; | |
268 | } | |
269 | ||
270 | if (invert) { | |
271 | k = strjoin("!", word); | |
272 | if (!k) | |
273 | return log_oom(); | |
274 | } else | |
275 | k = TAKE_PTR(word); | |
276 | ||
277 | r = strv_consume(sv, TAKE_PTR(k)); | |
278 | if (r < 0) | |
279 | return log_oom(); | |
280 | } | |
281 | } | |
282 | ||
283 | int config_parse_match_ifnames( | |
284 | const char *unit, | |
285 | const char *filename, | |
286 | unsigned line, | |
287 | const char *section, | |
288 | unsigned section_line, | |
289 | const char *lvalue, | |
290 | int ltype, | |
291 | const char *rvalue, | |
292 | void *data, | |
293 | void *userdata) { | |
294 | ||
99534007 DT |
295 | const char *p = ASSERT_PTR(rvalue); |
296 | char ***sv = ASSERT_PTR(data); | |
7e19cc54 YW |
297 | bool invert; |
298 | int r; | |
299 | ||
300 | assert(filename); | |
301 | assert(lvalue); | |
7e19cc54 YW |
302 | |
303 | if (isempty(rvalue)) { | |
304 | *sv = strv_free(*sv); | |
305 | return 0; | |
306 | } | |
307 | ||
308 | invert = *p == '!'; | |
309 | p += invert; | |
310 | ||
311 | for (;;) { | |
312 | _cleanup_free_ char *word = NULL, *k = NULL; | |
313 | ||
314 | r = extract_first_word(&p, &word, NULL, 0); | |
315 | if (r == 0) | |
316 | return 0; | |
317 | if (r == -ENOMEM) | |
318 | return log_oom(); | |
319 | if (r < 0) { | |
320 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
321 | "Failed to parse interface name list, ignoring: %s", rvalue); | |
322 | return 0; | |
323 | } | |
324 | ||
325 | if (!ifname_valid_full(word, ltype)) { | |
326 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
327 | "Interface name is not valid or too long, ignoring assignment: %s", word); | |
328 | continue; | |
329 | } | |
330 | ||
331 | if (invert) { | |
332 | k = strjoin("!", word); | |
333 | if (!k) | |
334 | return log_oom(); | |
335 | } else | |
336 | k = TAKE_PTR(word); | |
337 | ||
338 | r = strv_consume(sv, TAKE_PTR(k)); | |
339 | if (r < 0) | |
340 | return log_oom(); | |
341 | } | |
342 | } | |
343 | ||
344 | int config_parse_match_property( | |
345 | const char *unit, | |
346 | const char *filename, | |
347 | unsigned line, | |
348 | const char *section, | |
349 | unsigned section_line, | |
350 | const char *lvalue, | |
351 | int ltype, | |
352 | const char *rvalue, | |
353 | void *data, | |
354 | void *userdata) { | |
355 | ||
99534007 DT |
356 | const char *p = ASSERT_PTR(rvalue); |
357 | char ***sv = ASSERT_PTR(data); | |
7e19cc54 YW |
358 | bool invert; |
359 | int r; | |
360 | ||
361 | assert(filename); | |
362 | assert(lvalue); | |
7e19cc54 YW |
363 | |
364 | if (isempty(rvalue)) { | |
365 | *sv = strv_free(*sv); | |
366 | return 0; | |
367 | } | |
368 | ||
369 | invert = *p == '!'; | |
370 | p += invert; | |
371 | ||
372 | for (;;) { | |
373 | _cleanup_free_ char *word = NULL, *k = NULL; | |
374 | ||
375 | r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE); | |
376 | if (r == 0) | |
377 | return 0; | |
378 | if (r == -ENOMEM) | |
379 | return log_oom(); | |
380 | if (r < 0) { | |
381 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
382 | "Invalid syntax, ignoring: %s", rvalue); | |
383 | return 0; | |
384 | } | |
385 | ||
386 | if (!env_assignment_is_valid(word)) { | |
387 | log_syntax(unit, LOG_WARNING, filename, line, 0, | |
388 | "Invalid property or value, ignoring assignment: %s", word); | |
389 | continue; | |
390 | } | |
391 | ||
392 | if (invert) { | |
393 | k = strjoin("!", word); | |
394 | if (!k) | |
395 | return log_oom(); | |
396 | } else | |
397 | k = TAKE_PTR(word); | |
398 | ||
399 | r = strv_consume(sv, TAKE_PTR(k)); | |
400 | if (r < 0) | |
401 | return log_oom(); | |
402 | } | |
403 | } |