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