]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/resolve/resolved-link-bus.c
Merge pull request #8499 from fbuihuu/shadow-support-nis
[thirdparty/systemd.git] / src / resolve / resolved-link-bus.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2016 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include "alloc-util.h"
22 #include "bus-common-errors.h"
23 #include "bus-util.h"
24 #include "parse-util.h"
25 #include "resolve-util.h"
26 #include "resolved-bus.h"
27 #include "resolved-link-bus.h"
28 #include "resolved-resolv-conf.h"
29 #include "strv.h"
30
31 static int property_get_dnssec_mode(
32 sd_bus *bus,
33 const char *path,
34 const char *interface,
35 const char *property,
36 sd_bus_message *reply,
37 void *userdata,
38 sd_bus_error *error) {
39
40 Link *l = userdata;
41
42 assert(reply);
43 assert(l);
44
45 return sd_bus_message_append(reply, "s", dnssec_mode_to_string(link_get_dnssec_mode(l)));
46 }
47
48 static int property_get_dns(
49 sd_bus *bus,
50 const char *path,
51 const char *interface,
52 const char *property,
53 sd_bus_message *reply,
54 void *userdata,
55 sd_bus_error *error) {
56
57 Link *l = userdata;
58 DnsServer *s;
59 int r;
60
61 assert(reply);
62 assert(l);
63
64 r = sd_bus_message_open_container(reply, 'a', "(iay)");
65 if (r < 0)
66 return r;
67
68 LIST_FOREACH(servers, s, l->dns_servers) {
69 r = bus_dns_server_append(reply, s, false);
70 if (r < 0)
71 return r;
72 }
73
74 return sd_bus_message_close_container(reply);
75 }
76
77 static int property_get_domains(
78 sd_bus *bus,
79 const char *path,
80 const char *interface,
81 const char *property,
82 sd_bus_message *reply,
83 void *userdata,
84 sd_bus_error *error) {
85
86 Link *l = userdata;
87 DnsSearchDomain *d;
88 int r;
89
90 assert(reply);
91 assert(l);
92
93 r = sd_bus_message_open_container(reply, 'a', "(sb)");
94 if (r < 0)
95 return r;
96
97 LIST_FOREACH(domains, d, l->search_domains) {
98 r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
99 if (r < 0)
100 return r;
101 }
102
103 return sd_bus_message_close_container(reply);
104 }
105
106 static int property_get_scopes_mask(
107 sd_bus *bus,
108 const char *path,
109 const char *interface,
110 const char *property,
111 sd_bus_message *reply,
112 void *userdata,
113 sd_bus_error *error) {
114
115 Link *l = userdata;
116 uint64_t mask;
117
118 assert(reply);
119 assert(l);
120
121 mask = (l->unicast_scope ? SD_RESOLVED_DNS : 0) |
122 (l->llmnr_ipv4_scope ? SD_RESOLVED_LLMNR_IPV4 : 0) |
123 (l->llmnr_ipv6_scope ? SD_RESOLVED_LLMNR_IPV6 : 0) |
124 (l->mdns_ipv4_scope ? SD_RESOLVED_MDNS_IPV4 : 0) |
125 (l->mdns_ipv6_scope ? SD_RESOLVED_MDNS_IPV6 : 0);
126
127 return sd_bus_message_append(reply, "t", mask);
128 }
129
130 static int property_get_ntas(
131 sd_bus *bus,
132 const char *path,
133 const char *interface,
134 const char *property,
135 sd_bus_message *reply,
136 void *userdata,
137 sd_bus_error *error) {
138
139 Link *l = userdata;
140 const char *name;
141 Iterator i;
142 int r;
143
144 assert(reply);
145 assert(l);
146
147 r = sd_bus_message_open_container(reply, 'a', "s");
148 if (r < 0)
149 return r;
150
151 SET_FOREACH(name, l->dnssec_negative_trust_anchors, i) {
152 r = sd_bus_message_append(reply, "s", name);
153 if (r < 0)
154 return r;
155 }
156
157 return sd_bus_message_close_container(reply);
158 }
159
160 static int property_get_dnssec_supported(
161 sd_bus *bus,
162 const char *path,
163 const char *interface,
164 const char *property,
165 sd_bus_message *reply,
166 void *userdata,
167 sd_bus_error *error) {
168
169 Link *l = userdata;
170
171 assert(reply);
172 assert(l);
173
174 return sd_bus_message_append(reply, "b", link_dnssec_supported(l));
175 }
176
177 static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
178 assert(l);
179
180 if (l->flags & IFF_LOOPBACK)
181 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->name);
182 if (l->is_managed)
183 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->name);
184
185 return 0;
186 }
187
188 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
189 _cleanup_free_ struct in_addr_data *dns = NULL;
190 size_t allocated = 0, n = 0;
191 Link *l = userdata;
192 unsigned i;
193 int r;
194
195 assert(message);
196 assert(l);
197
198 r = verify_unmanaged_link(l, error);
199 if (r < 0)
200 return r;
201
202 r = sd_bus_message_enter_container(message, 'a', "(iay)");
203 if (r < 0)
204 return r;
205
206 for (;;) {
207 int family;
208 size_t sz;
209 const void *d;
210
211 assert_cc(sizeof(int) == sizeof(int32_t));
212
213 r = sd_bus_message_enter_container(message, 'r', "iay");
214 if (r < 0)
215 return r;
216 if (r == 0)
217 break;
218
219 r = sd_bus_message_read(message, "i", &family);
220 if (r < 0)
221 return r;
222
223 if (!IN_SET(family, AF_INET, AF_INET6))
224 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
225
226 r = sd_bus_message_read_array(message, 'y', &d, &sz);
227 if (r < 0)
228 return r;
229 if (sz != FAMILY_ADDRESS_SIZE(family))
230 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
231
232 if (!dns_server_address_valid(family, d))
233 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
234
235 r = sd_bus_message_exit_container(message);
236 if (r < 0)
237 return r;
238
239 if (!GREEDY_REALLOC(dns, allocated, n+1))
240 return -ENOMEM;
241
242 dns[n].family = family;
243 memcpy(&dns[n].address, d, sz);
244 n++;
245 }
246
247 r = sd_bus_message_exit_container(message);
248 if (r < 0)
249 return r;
250
251 dns_server_mark_all(l->dns_servers);
252
253 for (i = 0; i < n; i++) {
254 DnsServer *s;
255
256 s = dns_server_find(l->dns_servers, dns[i].family, &dns[i].address, 0);
257 if (s)
258 dns_server_move_back_and_unmark(s);
259 else {
260 r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i].family, &dns[i].address, 0);
261 if (r < 0)
262 goto clear;
263 }
264
265 }
266
267 dns_server_unlink_marked(l->dns_servers);
268 link_allocate_scopes(l);
269
270 (void) link_save_user(l);
271 (void) manager_write_resolv_conf(l->manager);
272
273 return sd_bus_reply_method_return(message, NULL);
274
275 clear:
276 dns_server_unlink_all(l->dns_servers);
277 return r;
278 }
279
280 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
281 Link *l = userdata;
282 int r;
283
284 assert(message);
285 assert(l);
286
287 r = verify_unmanaged_link(l, error);
288 if (r < 0)
289 return r;
290
291 r = sd_bus_message_enter_container(message, 'a', "(sb)");
292 if (r < 0)
293 return r;
294
295 for (;;) {
296 const char *name;
297 int route_only;
298
299 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
300 if (r < 0)
301 return r;
302 if (r == 0)
303 break;
304
305 r = dns_name_is_valid(name);
306 if (r < 0)
307 return r;
308 if (r == 0)
309 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
310 if (!route_only && dns_name_is_root(name))
311 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
312 }
313
314 dns_search_domain_mark_all(l->search_domains);
315
316 r = sd_bus_message_rewind(message, false);
317 if (r < 0)
318 return r;
319
320 for (;;) {
321 DnsSearchDomain *d;
322 const char *name;
323 int route_only;
324
325 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
326 if (r < 0)
327 goto clear;
328 if (r == 0)
329 break;
330
331 r = dns_search_domain_find(l->search_domains, name, &d);
332 if (r < 0)
333 goto clear;
334
335 if (r > 0)
336 dns_search_domain_move_back_and_unmark(d);
337 else {
338 r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
339 if (r < 0)
340 goto clear;
341 }
342
343 d->route_only = route_only;
344 }
345
346 r = sd_bus_message_exit_container(message);
347 if (r < 0)
348 goto clear;
349
350 dns_search_domain_unlink_marked(l->search_domains);
351
352 (void) link_save_user(l);
353 (void) manager_write_resolv_conf(l->manager);
354
355 return sd_bus_reply_method_return(message, NULL);
356
357 clear:
358 dns_search_domain_unlink_all(l->search_domains);
359 return r;
360 }
361
362 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
363 Link *l = userdata;
364 ResolveSupport mode;
365 const char *llmnr;
366 int r;
367
368 assert(message);
369 assert(l);
370
371 r = verify_unmanaged_link(l, error);
372 if (r < 0)
373 return r;
374
375 r = sd_bus_message_read(message, "s", &llmnr);
376 if (r < 0)
377 return r;
378
379 if (isempty(llmnr))
380 mode = RESOLVE_SUPPORT_YES;
381 else {
382 mode = resolve_support_from_string(llmnr);
383 if (mode < 0)
384 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
385 }
386
387 l->llmnr_support = mode;
388 link_allocate_scopes(l);
389 link_add_rrs(l, false);
390
391 (void) link_save_user(l);
392
393 return sd_bus_reply_method_return(message, NULL);
394 }
395
396 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
397 Link *l = userdata;
398 ResolveSupport mode;
399 const char *mdns;
400 int r;
401
402 assert(message);
403 assert(l);
404
405 r = verify_unmanaged_link(l, error);
406 if (r < 0)
407 return r;
408
409 r = sd_bus_message_read(message, "s", &mdns);
410 if (r < 0)
411 return r;
412
413 if (isempty(mdns))
414 mode = RESOLVE_SUPPORT_NO;
415 else {
416 mode = resolve_support_from_string(mdns);
417 if (mode < 0)
418 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
419 }
420
421 l->mdns_support = mode;
422 link_allocate_scopes(l);
423 link_add_rrs(l, false);
424
425 (void) link_save_user(l);
426
427 return sd_bus_reply_method_return(message, NULL);
428 }
429
430 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
431 Link *l = userdata;
432 const char *dnssec;
433 DnssecMode mode;
434 int r;
435
436 assert(message);
437 assert(l);
438
439 r = verify_unmanaged_link(l, error);
440 if (r < 0)
441 return r;
442
443 r = sd_bus_message_read(message, "s", &dnssec);
444 if (r < 0)
445 return r;
446
447 if (isempty(dnssec))
448 mode = _DNSSEC_MODE_INVALID;
449 else {
450 mode = dnssec_mode_from_string(dnssec);
451 if (mode < 0)
452 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
453 }
454
455 link_set_dnssec_mode(l, mode);
456
457 (void) link_save_user(l);
458
459 return sd_bus_reply_method_return(message, NULL);
460 }
461
462 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
463 _cleanup_set_free_free_ Set *ns = NULL;
464 _cleanup_strv_free_ char **ntas = NULL;
465 Link *l = userdata;
466 int r;
467 char **i;
468
469 assert(message);
470 assert(l);
471
472 r = verify_unmanaged_link(l, error);
473 if (r < 0)
474 return r;
475
476 r = sd_bus_message_read_strv(message, &ntas);
477 if (r < 0)
478 return r;
479
480 STRV_FOREACH(i, ntas) {
481 r = dns_name_is_valid(*i);
482 if (r < 0)
483 return r;
484 if (r == 0)
485 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
486 }
487
488 ns = set_new(&dns_name_hash_ops);
489 if (!ns)
490 return -ENOMEM;
491
492 STRV_FOREACH(i, ntas) {
493 r = set_put_strdup(ns, *i);
494 if (r < 0)
495 return r;
496 }
497
498 set_free_free(l->dnssec_negative_trust_anchors);
499 l->dnssec_negative_trust_anchors = ns;
500 ns = NULL;
501
502 (void) link_save_user(l);
503
504 return sd_bus_reply_method_return(message, NULL);
505 }
506
507 int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
508 Link *l = userdata;
509 int r;
510
511 assert(message);
512 assert(l);
513
514 r = verify_unmanaged_link(l, error);
515 if (r < 0)
516 return r;
517
518 link_flush_settings(l);
519 link_allocate_scopes(l);
520 link_add_rrs(l, false);
521
522 (void) link_save_user(l);
523 (void) manager_write_resolv_conf(l->manager);
524
525 return sd_bus_reply_method_return(message, NULL);
526 }
527
528 const sd_bus_vtable link_vtable[] = {
529 SD_BUS_VTABLE_START(0),
530
531 SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
532 SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
533 SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
534 SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
535 SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
536 SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
537 SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
538 SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
539
540 SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, 0),
541 SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, 0),
542 SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, 0),
543 SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, 0),
544 SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, 0),
545 SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, 0),
546 SD_BUS_METHOD("Revert", NULL, NULL, bus_link_method_revert, 0),
547
548 SD_BUS_VTABLE_END
549 };
550
551 int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
552 _cleanup_free_ char *e = NULL;
553 Manager *m = userdata;
554 int ifindex;
555 Link *link;
556 int r;
557
558 assert(bus);
559 assert(path);
560 assert(interface);
561 assert(found);
562 assert(m);
563
564 r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
565 if (r <= 0)
566 return 0;
567
568 r = parse_ifindex(e, &ifindex);
569 if (r < 0)
570 return 0;
571
572 link = hashmap_get(m->links, INT_TO_PTR(ifindex));
573 if (!link)
574 return 0;
575
576 *found = link;
577 return 1;
578 }
579
580 char *link_bus_path(Link *link) {
581 _cleanup_free_ char *ifindex = NULL;
582 char *p;
583 int r;
584
585 assert(link);
586
587 if (asprintf(&ifindex, "%i", link->ifindex) < 0)
588 return NULL;
589
590 r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
591 if (r < 0)
592 return NULL;
593
594 return p;
595 }
596
597 int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
598 _cleanup_strv_free_ char **l = NULL;
599 Manager *m = userdata;
600 Link *link;
601 Iterator i;
602 unsigned c = 0;
603
604 assert(bus);
605 assert(path);
606 assert(m);
607 assert(nodes);
608
609 l = new0(char*, hashmap_size(m->links) + 1);
610 if (!l)
611 return -ENOMEM;
612
613 HASHMAP_FOREACH(link, m->links, i) {
614 char *p;
615
616 p = link_bus_path(link);
617 if (!p)
618 return -ENOMEM;
619
620 l[c++] = p;
621 }
622
623 l[c] = NULL;
624 *nodes = l;
625 l = NULL;
626
627 return 1;
628 }