]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/net-condition.c
strv: make iterator in STRV_FOREACH() declaread in the loop
[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
236 const char *p = rvalue;
237 char ***sv = data;
238 bool invert;
239 int r;
240
241 assert(filename);
242 assert(lvalue);
243 assert(rvalue);
244 assert(data);
245
246 if (isempty(rvalue)) {
247 *sv = strv_free(*sv);
248 return 0;
249 }
250
251 invert = *p == '!';
252 p += invert;
253
254 for (;;) {
255 _cleanup_free_ char *word = NULL, *k = NULL;
256
257 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
258 if (r == 0)
259 return 0;
260 if (r == -ENOMEM)
261 return log_oom();
262 if (r < 0) {
263 log_syntax(unit, LOG_WARNING, filename, line, r,
264 "Invalid syntax, ignoring: %s", rvalue);
265 return 0;
266 }
267
268 if (invert) {
269 k = strjoin("!", word);
270 if (!k)
271 return log_oom();
272 } else
273 k = TAKE_PTR(word);
274
275 r = strv_consume(sv, TAKE_PTR(k));
276 if (r < 0)
277 return log_oom();
278 }
279}
280
281int config_parse_match_ifnames(
282 const char *unit,
283 const char *filename,
284 unsigned line,
285 const char *section,
286 unsigned section_line,
287 const char *lvalue,
288 int ltype,
289 const char *rvalue,
290 void *data,
291 void *userdata) {
292
293 const char *p = rvalue;
294 char ***sv = data;
295 bool invert;
296 int r;
297
298 assert(filename);
299 assert(lvalue);
300 assert(rvalue);
301 assert(data);
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
344int 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
356 const char *p = rvalue;
357 char ***sv = data;
358 bool invert;
359 int r;
360
361 assert(filename);
362 assert(lvalue);
363 assert(rvalue);
364 assert(data);
365
366 if (isempty(rvalue)) {
367 *sv = strv_free(*sv);
368 return 0;
369 }
370
371 invert = *p == '!';
372 p += invert;
373
374 for (;;) {
375 _cleanup_free_ char *word = NULL, *k = NULL;
376
377 r = extract_first_word(&p, &word, NULL, EXTRACT_CUNESCAPE|EXTRACT_UNQUOTE);
378 if (r == 0)
379 return 0;
380 if (r == -ENOMEM)
381 return log_oom();
382 if (r < 0) {
383 log_syntax(unit, LOG_WARNING, filename, line, 0,
384 "Invalid syntax, ignoring: %s", rvalue);
385 return 0;
386 }
387
388 if (!env_assignment_is_valid(word)) {
389 log_syntax(unit, LOG_WARNING, filename, line, 0,
390 "Invalid property or value, ignoring assignment: %s", word);
391 continue;
392 }
393
394 if (invert) {
395 k = strjoin("!", word);
396 if (!k)
397 return log_oom();
398 } else
399 k = TAKE_PTR(word);
400
401 r = strv_consume(sv, TAKE_PTR(k));
402 if (r < 0)
403 return log_oom();
404 }
405}