1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <sys/capability.h>
6 
7 #include "alloc-util.h"
8 #include "bus-common-errors.h"
9 #include "bus-get-properties.h"
10 #include "bus-message-util.h"
11 #include "bus-polkit.h"
12 #include "log-link.h"
13 #include "parse-util.h"
14 #include "resolve-util.h"
15 #include "resolved-bus.h"
16 #include "resolved-link-bus.h"
17 #include "resolved-resolv-conf.h"
18 #include "socket-netlink.h"
19 #include "stdio-util.h"
20 #include "strv.h"
21 #include "user-util.h"
22 
23 static BUS_DEFINE_PROPERTY_GET(property_get_dnssec_supported, "b", Link, link_dnssec_supported);
24 static BUS_DEFINE_PROPERTY_GET2(property_get_dnssec_mode, "s", Link, link_get_dnssec_mode, dnssec_mode_to_string);
25 
property_get_dns_over_tls_mode(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)26 static int property_get_dns_over_tls_mode(
27                 sd_bus *bus,
28                 const char *path,
29                 const char *interface,
30                 const char *property,
31                 sd_bus_message *reply,
32                 void *userdata,
33                 sd_bus_error *error) {
34 
35         Link *l = userdata;
36 
37         assert(reply);
38         assert(l);
39 
40         return sd_bus_message_append(reply, "s", dns_over_tls_mode_to_string(link_get_dns_over_tls_mode(l)));
41 }
42 
property_get_dns_internal(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error,bool extended)43 static int property_get_dns_internal(
44                 sd_bus *bus,
45                 const char *path,
46                 const char *interface,
47                 const char *property,
48                 sd_bus_message *reply,
49                 void *userdata,
50                 sd_bus_error *error,
51                 bool extended) {
52 
53         Link *l = userdata;
54         int r;
55 
56         assert(reply);
57         assert(l);
58 
59         r = sd_bus_message_open_container(reply, 'a', extended ? "(iayqs)" : "(iay)");
60         if (r < 0)
61                 return r;
62 
63         LIST_FOREACH(servers, s, l->dns_servers) {
64                 r = bus_dns_server_append(reply, s, false, extended);
65                 if (r < 0)
66                         return r;
67         }
68 
69         return sd_bus_message_close_container(reply);
70 }
71 
property_get_dns(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)72 static int property_get_dns(
73                 sd_bus *bus,
74                 const char *path,
75                 const char *interface,
76                 const char *property,
77                 sd_bus_message *reply,
78                 void *userdata,
79                 sd_bus_error *error) {
80         return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, false);
81 }
82 
property_get_dns_ex(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)83 static int property_get_dns_ex(
84                 sd_bus *bus,
85                 const char *path,
86                 const char *interface,
87                 const char *property,
88                 sd_bus_message *reply,
89                 void *userdata,
90                 sd_bus_error *error) {
91         return property_get_dns_internal(bus, path, interface, property, reply, userdata, error, true);
92 }
93 
property_get_current_dns_server_internal(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error,bool extended)94 static int property_get_current_dns_server_internal(
95                 sd_bus *bus,
96                 const char *path,
97                 const char *interface,
98                 const char *property,
99                 sd_bus_message *reply,
100                 void *userdata,
101                 sd_bus_error *error,
102                 bool extended) {
103 
104         DnsServer *s;
105 
106         assert(reply);
107         assert(userdata);
108 
109         s = *(DnsServer **) userdata;
110 
111         return bus_dns_server_append(reply, s, false, extended);
112 }
113 
property_get_current_dns_server(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)114 static int property_get_current_dns_server(
115                 sd_bus *bus,
116                 const char *path,
117                 const char *interface,
118                 const char *property,
119                 sd_bus_message *reply,
120                 void *userdata,
121                 sd_bus_error *error) {
122         return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, false);
123 }
124 
property_get_current_dns_server_ex(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)125 static int property_get_current_dns_server_ex(
126                 sd_bus *bus,
127                 const char *path,
128                 const char *interface,
129                 const char *property,
130                 sd_bus_message *reply,
131                 void *userdata,
132                 sd_bus_error *error) {
133         return property_get_current_dns_server_internal(bus, path, interface, property, reply, userdata, error, true);
134 }
135 
property_get_domains(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)136 static int property_get_domains(
137                 sd_bus *bus,
138                 const char *path,
139                 const char *interface,
140                 const char *property,
141                 sd_bus_message *reply,
142                 void *userdata,
143                 sd_bus_error *error) {
144 
145         Link *l = userdata;
146         int r;
147 
148         assert(reply);
149         assert(l);
150 
151         r = sd_bus_message_open_container(reply, 'a', "(sb)");
152         if (r < 0)
153                 return r;
154 
155         LIST_FOREACH(domains, d, l->search_domains) {
156                 r = sd_bus_message_append(reply, "(sb)", d->name, d->route_only);
157                 if (r < 0)
158                         return r;
159         }
160 
161         return sd_bus_message_close_container(reply);
162 }
163 
property_get_default_route(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)164 static int property_get_default_route(
165                 sd_bus *bus,
166                 const char *path,
167                 const char *interface,
168                 const char *property,
169                 sd_bus_message *reply,
170                 void *userdata,
171                 sd_bus_error *error) {
172 
173         Link *l = userdata;
174 
175         assert(reply);
176         assert(l);
177 
178         /* Return what is configured, if there's something configured */
179         if (l->default_route >= 0)
180                 return sd_bus_message_append(reply, "b", l->default_route);
181 
182         /* Otherwise report what is in effect */
183         if (l->unicast_scope)
184                 return sd_bus_message_append(reply, "b", dns_scope_is_default_route(l->unicast_scope));
185 
186         return sd_bus_message_append(reply, "b", false);
187 }
188 
property_get_scopes_mask(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)189 static int property_get_scopes_mask(
190                 sd_bus *bus,
191                 const char *path,
192                 const char *interface,
193                 const char *property,
194                 sd_bus_message *reply,
195                 void *userdata,
196                 sd_bus_error *error) {
197 
198         Link *l = userdata;
199         uint64_t mask;
200 
201         assert(reply);
202         assert(l);
203 
204         mask =  (l->unicast_scope ? SD_RESOLVED_DNS : 0) |
205                 (l->llmnr_ipv4_scope ? SD_RESOLVED_LLMNR_IPV4 : 0) |
206                 (l->llmnr_ipv6_scope ? SD_RESOLVED_LLMNR_IPV6 : 0) |
207                 (l->mdns_ipv4_scope ? SD_RESOLVED_MDNS_IPV4 : 0) |
208                 (l->mdns_ipv6_scope ? SD_RESOLVED_MDNS_IPV6 : 0);
209 
210         return sd_bus_message_append(reply, "t", mask);
211 }
212 
property_get_ntas(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)213 static int property_get_ntas(
214                 sd_bus *bus,
215                 const char *path,
216                 const char *interface,
217                 const char *property,
218                 sd_bus_message *reply,
219                 void *userdata,
220                 sd_bus_error *error) {
221 
222         Link *l = userdata;
223         const char *name;
224         int r;
225 
226         assert(reply);
227         assert(l);
228 
229         r = sd_bus_message_open_container(reply, 'a', "s");
230         if (r < 0)
231                 return r;
232 
233         SET_FOREACH(name, l->dnssec_negative_trust_anchors) {
234                 r = sd_bus_message_append(reply, "s", name);
235                 if (r < 0)
236                         return r;
237         }
238 
239         return sd_bus_message_close_container(reply);
240 }
241 
verify_unmanaged_link(Link * l,sd_bus_error * error)242 static int verify_unmanaged_link(Link *l, sd_bus_error *error) {
243         assert(l);
244 
245         if (l->flags & IFF_LOOPBACK)
246                 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
247         if (l->is_managed)
248                 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is managed.", l->ifname);
249 
250         return 0;
251 }
252 
bus_link_method_set_dns_servers_internal(sd_bus_message * message,void * userdata,sd_bus_error * error,bool extended)253 static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
254         _cleanup_free_ char *j = NULL;
255         struct in_addr_full **dns;
256         bool changed = false;
257         Link *l = userdata;
258         size_t n;
259         int r;
260 
261         assert(message);
262         assert(l);
263 
264         r = verify_unmanaged_link(l, error);
265         if (r < 0)
266                 return r;
267 
268         r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
269         if (r < 0)
270                 return r;
271 
272         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
273                                     "org.freedesktop.resolve1.set-dns-servers",
274                                     NULL, true, UID_INVALID,
275                                     &l->manager->polkit_registry, error);
276         if (r < 0)
277                 goto finalize;
278         if (r == 0) {
279                 r = 1; /* Polkit will call us back */
280                 goto finalize;
281         }
282 
283         for (size_t i = 0; i < n; i++) {
284                 const char *s;
285 
286                 s = in_addr_full_to_string(dns[i]);
287                 if (!s) {
288                         r = -ENOMEM;
289                         goto finalize;
290                 }
291 
292                 if (!strextend_with_separator(&j, ", ", s)) {
293                         r = -ENOMEM;
294                         goto finalize;
295                 }
296         }
297 
298         bus_client_log(message, "DNS server change");
299 
300         dns_server_mark_all(l->dns_servers);
301 
302         for (size_t i = 0; i < n; i++) {
303                 DnsServer *s;
304 
305                 s = dns_server_find(l->dns_servers, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
306                 if (s)
307                         dns_server_move_back_and_unmark(s);
308                 else {
309                         r = dns_server_new(l->manager, NULL, DNS_SERVER_LINK, l, dns[i]->family, &dns[i]->address, dns[i]->port, 0, dns[i]->server_name);
310                         if (r < 0) {
311                                 dns_server_unlink_all(l->dns_servers);
312                                 goto finalize;
313                         }
314 
315                         changed = true;
316                 }
317 
318         }
319 
320         changed = dns_server_unlink_marked(l->dns_servers) || changed;
321 
322         if (changed) {
323                 link_allocate_scopes(l);
324 
325                 (void) link_save_user(l);
326                 (void) manager_write_resolv_conf(l->manager);
327                 (void) manager_send_changed(l->manager, "DNS");
328 
329                 if (j)
330                         log_link_info(l, "Bus client set DNS server list to: %s", j);
331                 else
332                         log_link_info(l, "Bus client reset DNS server list.");
333         }
334 
335         r = sd_bus_reply_method_return(message, NULL);
336 
337 finalize:
338         for (size_t i = 0; i < n; i++)
339                 in_addr_full_free(dns[i]);
340         free(dns);
341 
342         return r;
343 }
344 
bus_link_method_set_dns_servers(sd_bus_message * message,void * userdata,sd_bus_error * error)345 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
346         return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
347 }
348 
bus_link_method_set_dns_servers_ex(sd_bus_message * message,void * userdata,sd_bus_error * error)349 int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
350         return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
351 }
352 
bus_link_method_set_domains(sd_bus_message * message,void * userdata,sd_bus_error * error)353 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
354         _cleanup_free_ char *j = NULL;
355         Link *l = userdata;
356         bool changed = false;
357         int r;
358 
359         assert(message);
360         assert(l);
361 
362         r = verify_unmanaged_link(l, error);
363         if (r < 0)
364                 return r;
365 
366         r = sd_bus_message_enter_container(message, 'a', "(sb)");
367         if (r < 0)
368                 return r;
369 
370         for (;;) {
371                 _cleanup_free_ char *prefixed = NULL;
372                 const char *name;
373                 int route_only;
374 
375                 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
376                 if (r < 0)
377                         return r;
378                 if (r == 0)
379                         break;
380 
381                 r = dns_name_is_valid(name);
382                 if (r < 0)
383                         return r;
384                 if (r == 0)
385                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
386                 if (!route_only && dns_name_is_root(name))
387                         return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
388 
389                 if (route_only) {
390                         prefixed = strjoin("~", name);
391                         if (!prefixed)
392                                 return -ENOMEM;
393 
394                         name = prefixed;
395                 }
396 
397                 if (!strextend_with_separator(&j, ", ", name))
398                         return -ENOMEM;
399         }
400 
401         r = sd_bus_message_rewind(message, false);
402         if (r < 0)
403                 return r;
404 
405         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
406                                     "org.freedesktop.resolve1.set-domains",
407                                     NULL, true, UID_INVALID,
408                                     &l->manager->polkit_registry, error);
409         if (r < 0)
410                 return r;
411         if (r == 0)
412                 return 1; /* Polkit will call us back */
413 
414         bus_client_log(message, "dns domains change");
415 
416         dns_search_domain_mark_all(l->search_domains);
417 
418         for (;;) {
419                 DnsSearchDomain *d;
420                 const char *name;
421                 int route_only;
422 
423                 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
424                 if (r < 0)
425                         goto clear;
426                 if (r == 0)
427                         break;
428 
429                 r = dns_search_domain_find(l->search_domains, name, &d);
430                 if (r < 0)
431                         goto clear;
432 
433                 if (r > 0)
434                         dns_search_domain_move_back_and_unmark(d);
435                 else {
436                         r = dns_search_domain_new(l->manager, &d, DNS_SEARCH_DOMAIN_LINK, l, name);
437                         if (r < 0)
438                                 goto clear;
439 
440                         changed = true;
441                 }
442 
443                 d->route_only = route_only;
444         }
445 
446         r = sd_bus_message_exit_container(message);
447         if (r < 0)
448                 goto clear;
449 
450         changed = dns_search_domain_unlink_marked(l->search_domains) || changed;
451 
452         if (changed) {
453                 (void) link_save_user(l);
454                 (void) manager_write_resolv_conf(l->manager);
455 
456                 if (j)
457                         log_link_info(l, "Bus client set search domain list to: %s", j);
458                 else
459                         log_link_info(l, "Bus client reset search domain list.");
460         }
461 
462         return sd_bus_reply_method_return(message, NULL);
463 
464 clear:
465         dns_search_domain_unlink_all(l->search_domains);
466         return r;
467 }
468 
bus_link_method_set_default_route(sd_bus_message * message,void * userdata,sd_bus_error * error)469 int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
470         Link *l = userdata;
471         int r, b;
472 
473         assert(message);
474         assert(l);
475 
476         r = verify_unmanaged_link(l, error);
477         if (r < 0)
478                 return r;
479 
480         r = sd_bus_message_read(message, "b", &b);
481         if (r < 0)
482                 return r;
483 
484         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
485                                     "org.freedesktop.resolve1.set-default-route",
486                                     NULL, true, UID_INVALID,
487                                     &l->manager->polkit_registry, error);
488         if (r < 0)
489                 return r;
490         if (r == 0)
491                 return 1; /* Polkit will call us back */
492 
493         bus_client_log(message, "dns default route change");
494 
495         if (l->default_route != b) {
496                 l->default_route = b;
497 
498                 (void) link_save_user(l);
499                 (void) manager_write_resolv_conf(l->manager);
500 
501                 log_link_info(l, "Bus client set default route setting: %s", yes_no(b));
502         }
503 
504         return sd_bus_reply_method_return(message, NULL);
505 }
506 
bus_link_method_set_llmnr(sd_bus_message * message,void * userdata,sd_bus_error * error)507 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
508         Link *l = userdata;
509         ResolveSupport mode;
510         const char *llmnr;
511         int r;
512 
513         assert(message);
514         assert(l);
515 
516         r = verify_unmanaged_link(l, error);
517         if (r < 0)
518                 return r;
519 
520         r = sd_bus_message_read(message, "s", &llmnr);
521         if (r < 0)
522                 return r;
523 
524         if (isempty(llmnr))
525                 mode = RESOLVE_SUPPORT_YES;
526         else {
527                 mode = resolve_support_from_string(llmnr);
528                 if (mode < 0)
529                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
530         }
531 
532         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
533                                     "org.freedesktop.resolve1.set-llmnr",
534                                     NULL, true, UID_INVALID,
535                                     &l->manager->polkit_registry, error);
536         if (r < 0)
537                 return r;
538         if (r == 0)
539                 return 1; /* Polkit will call us back */
540 
541         bus_client_log(message, "LLMNR change");
542 
543         if (l->llmnr_support != mode) {
544                 l->llmnr_support = mode;
545                 link_allocate_scopes(l);
546                 link_add_rrs(l, false);
547 
548                 (void) link_save_user(l);
549 
550                 log_link_info(l, "Bus client set LLMNR setting: %s", resolve_support_to_string(mode));
551         }
552 
553         return sd_bus_reply_method_return(message, NULL);
554 }
555 
bus_link_method_set_mdns(sd_bus_message * message,void * userdata,sd_bus_error * error)556 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
557         Link *l = userdata;
558         ResolveSupport mode;
559         const char *mdns;
560         int r;
561 
562         assert(message);
563         assert(l);
564 
565         r = verify_unmanaged_link(l, error);
566         if (r < 0)
567                 return r;
568 
569         r = sd_bus_message_read(message, "s", &mdns);
570         if (r < 0)
571                 return r;
572 
573         if (isempty(mdns))
574                 mode = RESOLVE_SUPPORT_NO;
575         else {
576                 mode = resolve_support_from_string(mdns);
577                 if (mode < 0)
578                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
579         }
580 
581         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
582                                     "org.freedesktop.resolve1.set-mdns",
583                                     NULL, true, UID_INVALID,
584                                     &l->manager->polkit_registry, error);
585         if (r < 0)
586                 return r;
587         if (r == 0)
588                 return 1; /* Polkit will call us back */
589 
590         bus_client_log(message, "mDNS change");
591 
592         if (l->mdns_support != mode) {
593                 l->mdns_support = mode;
594                 link_allocate_scopes(l);
595                 link_add_rrs(l, false);
596 
597                 (void) link_save_user(l);
598 
599                 log_link_info(l, "Bus client set MulticastDNS setting: %s", resolve_support_to_string(mode));
600         }
601 
602         return sd_bus_reply_method_return(message, NULL);
603 }
604 
bus_link_method_set_dns_over_tls(sd_bus_message * message,void * userdata,sd_bus_error * error)605 int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
606         Link *l = userdata;
607         const char *dns_over_tls;
608         DnsOverTlsMode mode;
609         int r;
610 
611         assert(message);
612         assert(l);
613 
614         r = verify_unmanaged_link(l, error);
615         if (r < 0)
616                 return r;
617 
618         r = sd_bus_message_read(message, "s", &dns_over_tls);
619         if (r < 0)
620                 return r;
621 
622         if (isempty(dns_over_tls))
623                 mode = _DNS_OVER_TLS_MODE_INVALID;
624         else {
625                 mode = dns_over_tls_mode_from_string(dns_over_tls);
626                 if (mode < 0)
627                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
628         }
629 
630         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
631                                     "org.freedesktop.resolve1.set-dns-over-tls",
632                                     NULL, true, UID_INVALID,
633                                     &l->manager->polkit_registry, error);
634         if (r < 0)
635                 return r;
636         if (r == 0)
637                 return 1; /* Polkit will call us back */
638 
639         bus_client_log(message, "D-o-T change");
640 
641         if (l->dns_over_tls_mode != mode) {
642                 link_set_dns_over_tls_mode(l, mode);
643                 link_allocate_scopes(l);
644 
645                 (void) link_save_user(l);
646 
647                 log_link_info(l, "Bus client set DNSOverTLS setting: %s",
648                               mode < 0 ? "default" : dns_over_tls_mode_to_string(mode));
649         }
650 
651         return sd_bus_reply_method_return(message, NULL);
652 }
653 
bus_link_method_set_dnssec(sd_bus_message * message,void * userdata,sd_bus_error * error)654 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
655         Link *l = userdata;
656         const char *dnssec;
657         DnssecMode mode;
658         int r;
659 
660         assert(message);
661         assert(l);
662 
663         r = verify_unmanaged_link(l, error);
664         if (r < 0)
665                 return r;
666 
667         r = sd_bus_message_read(message, "s", &dnssec);
668         if (r < 0)
669                 return r;
670 
671         if (isempty(dnssec))
672                 mode = _DNSSEC_MODE_INVALID;
673         else {
674                 mode = dnssec_mode_from_string(dnssec);
675                 if (mode < 0)
676                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
677         }
678 
679         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
680                                     "org.freedesktop.resolve1.set-dnssec",
681                                     NULL, true, UID_INVALID,
682                                     &l->manager->polkit_registry, error);
683         if (r < 0)
684                 return r;
685         if (r == 0)
686                 return 1; /* Polkit will call us back */
687 
688         bus_client_log(message, "DNSSEC change");
689 
690         if (l->dnssec_mode != mode) {
691                 link_set_dnssec_mode(l, mode);
692                 link_allocate_scopes(l);
693 
694                 (void) link_save_user(l);
695 
696                 log_link_info(l, "Bus client set DNSSEC setting: %s",
697                               mode < 0 ? "default" : dnssec_mode_to_string(mode));
698         }
699 
700         return sd_bus_reply_method_return(message, NULL);
701 }
702 
bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message * message,void * userdata,sd_bus_error * error)703 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
704         _cleanup_set_free_free_ Set *ns = NULL;
705         _cleanup_strv_free_ char **ntas = NULL;
706         _cleanup_free_ char *j = NULL;
707         Link *l = userdata;
708         int r;
709 
710         assert(message);
711         assert(l);
712 
713         r = verify_unmanaged_link(l, error);
714         if (r < 0)
715                 return r;
716 
717         ns = set_new(&dns_name_hash_ops);
718         if (!ns)
719                 return -ENOMEM;
720 
721         r = sd_bus_message_read_strv(message, &ntas);
722         if (r < 0)
723                 return r;
724 
725         STRV_FOREACH(i, ntas) {
726                 r = dns_name_is_valid(*i);
727                 if (r < 0)
728                         return r;
729                 if (r == 0)
730                         return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
731                                                  "Invalid negative trust anchor domain: %s", *i);
732 
733                 r = set_put_strdup(&ns, *i);
734                 if (r < 0)
735                         return r;
736 
737                 if (!strextend_with_separator(&j, ", ", *i))
738                         return -ENOMEM;
739         }
740 
741         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
742                                     "org.freedesktop.resolve1.set-dnssec-negative-trust-anchors",
743                                     NULL, true, UID_INVALID,
744                                     &l->manager->polkit_registry, error);
745         if (r < 0)
746                 return r;
747         if (r == 0)
748                 return 1; /* Polkit will call us back */
749 
750         bus_client_log(message, "DNSSEC NTA change");
751 
752         if (!set_equal(ns, l->dnssec_negative_trust_anchors)) {
753                 set_free_free(l->dnssec_negative_trust_anchors);
754                 l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
755 
756                 (void) link_save_user(l);
757 
758                 if (j)
759                         log_link_info(l, "Bus client set NTA list to: %s", j);
760                 else
761                         log_link_info(l, "Bus client reset NTA list.");
762         }
763 
764         return sd_bus_reply_method_return(message, NULL);
765 }
766 
bus_link_method_revert(sd_bus_message * message,void * userdata,sd_bus_error * error)767 int bus_link_method_revert(sd_bus_message *message, void *userdata, sd_bus_error *error) {
768         Link *l = userdata;
769         int r;
770 
771         assert(message);
772         assert(l);
773 
774         r = verify_unmanaged_link(l, error);
775         if (r < 0)
776                 return r;
777 
778         r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
779                                     "org.freedesktop.resolve1.revert",
780                                     NULL, true, UID_INVALID,
781                                     &l->manager->polkit_registry, error);
782         if (r < 0)
783                 return r;
784         if (r == 0)
785                 return 1; /* Polkit will call us back */
786 
787         bus_client_log(message, "revert");
788 
789         link_flush_settings(l);
790         link_allocate_scopes(l);
791         link_add_rrs(l, false);
792 
793         (void) link_save_user(l);
794         (void) manager_write_resolv_conf(l->manager);
795         (void) manager_send_changed(l->manager, "DNS");
796 
797         return sd_bus_reply_method_return(message, NULL);
798 }
799 
link_object_find(sd_bus * bus,const char * path,const char * interface,void * userdata,void ** found,sd_bus_error * error)800 static int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
801         _cleanup_free_ char *e = NULL;
802         Manager *m = userdata;
803         Link *link;
804         int ifindex, r;
805 
806         assert(bus);
807         assert(path);
808         assert(interface);
809         assert(found);
810         assert(m);
811 
812         r = sd_bus_path_decode(path, "/org/freedesktop/resolve1/link", &e);
813         if (r <= 0)
814                 return 0;
815 
816         ifindex = parse_ifindex(e);
817         if (ifindex < 0)
818                 return 0;
819 
820         link = hashmap_get(m->links, INT_TO_PTR(ifindex));
821         if (!link)
822                 return 0;
823 
824         *found = link;
825         return 1;
826 }
827 
link_bus_path(const Link * link)828 char *link_bus_path(const Link *link) {
829         char *p, ifindex[DECIMAL_STR_MAX(link->ifindex)];
830         int r;
831 
832         assert(link);
833 
834         xsprintf(ifindex, "%i", link->ifindex);
835 
836         r = sd_bus_path_encode("/org/freedesktop/resolve1/link", ifindex, &p);
837         if (r < 0)
838                 return NULL;
839 
840         return p;
841 }
842 
link_node_enumerator(sd_bus * bus,const char * path,void * userdata,char *** nodes,sd_bus_error * error)843 static int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
844         _cleanup_strv_free_ char **l = NULL;
845         Manager *m = userdata;
846         Link *link;
847         unsigned c = 0;
848 
849         assert(bus);
850         assert(path);
851         assert(m);
852         assert(nodes);
853 
854         l = new0(char*, hashmap_size(m->links) + 1);
855         if (!l)
856                 return -ENOMEM;
857 
858         HASHMAP_FOREACH(link, m->links) {
859                 char *p;
860 
861                 p = link_bus_path(link);
862                 if (!p)
863                         return -ENOMEM;
864 
865                 l[c++] = p;
866         }
867 
868         l[c] = NULL;
869         *nodes = TAKE_PTR(l);
870 
871         return 1;
872 }
873 
874 static const sd_bus_vtable link_vtable[] = {
875         SD_BUS_VTABLE_START(0),
876 
877         SD_BUS_PROPERTY("ScopesMask", "t", property_get_scopes_mask, 0, 0),
878         SD_BUS_PROPERTY("DNS", "a(iay)", property_get_dns, 0, 0),
879         SD_BUS_PROPERTY("DNSEx", "a(iayqs)", property_get_dns_ex, 0, 0),
880         SD_BUS_PROPERTY("CurrentDNSServer", "(iay)", property_get_current_dns_server, offsetof(Link, current_dns_server), 0),
881         SD_BUS_PROPERTY("CurrentDNSServerEx", "(iayqs)", property_get_current_dns_server_ex, offsetof(Link, current_dns_server), 0),
882         SD_BUS_PROPERTY("Domains", "a(sb)", property_get_domains, 0, 0),
883         SD_BUS_PROPERTY("DefaultRoute", "b", property_get_default_route, 0, 0),
884         SD_BUS_PROPERTY("LLMNR", "s", bus_property_get_resolve_support, offsetof(Link, llmnr_support), 0),
885         SD_BUS_PROPERTY("MulticastDNS", "s", bus_property_get_resolve_support, offsetof(Link, mdns_support), 0),
886         SD_BUS_PROPERTY("DNSOverTLS", "s", property_get_dns_over_tls_mode, 0, 0),
887         SD_BUS_PROPERTY("DNSSEC", "s", property_get_dnssec_mode, 0, 0),
888         SD_BUS_PROPERTY("DNSSECNegativeTrustAnchors", "as", property_get_ntas, 0, 0),
889         SD_BUS_PROPERTY("DNSSECSupported", "b", property_get_dnssec_supported, 0, 0),
890 
891         SD_BUS_METHOD_WITH_ARGS("SetDNS",
892                                 SD_BUS_ARGS("a(iay)", addresses),
893                                 SD_BUS_NO_RESULT,
894                                 bus_link_method_set_dns_servers,
895                                 SD_BUS_VTABLE_UNPRIVILEGED),
896         SD_BUS_METHOD_WITH_ARGS("SetDNSEx",
897                                 SD_BUS_ARGS("a(iayqs)", addresses),
898                                 SD_BUS_NO_RESULT,
899                                 bus_link_method_set_dns_servers_ex,
900                                 SD_BUS_VTABLE_UNPRIVILEGED),
901         SD_BUS_METHOD_WITH_ARGS("SetDomains",
902                                 SD_BUS_ARGS("a(sb)", domains),
903                                 SD_BUS_NO_RESULT,
904                                 bus_link_method_set_domains,
905                                 SD_BUS_VTABLE_UNPRIVILEGED),
906         SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute",
907                                 SD_BUS_ARGS("b", enable),
908                                 SD_BUS_NO_RESULT,
909                                 bus_link_method_set_default_route,
910                                 SD_BUS_VTABLE_UNPRIVILEGED),
911         SD_BUS_METHOD_WITH_ARGS("SetLLMNR",
912                                 SD_BUS_ARGS("s", mode),
913                                 SD_BUS_NO_RESULT,
914                                 bus_link_method_set_llmnr,
915                                 SD_BUS_VTABLE_UNPRIVILEGED),
916         SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS",
917                                 SD_BUS_ARGS("s", mode),
918                                 SD_BUS_NO_RESULT,
919                                 bus_link_method_set_mdns,
920                                 SD_BUS_VTABLE_UNPRIVILEGED),
921         SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS",
922                                 SD_BUS_ARGS("s", mode),
923                                 SD_BUS_NO_RESULT,
924                                 bus_link_method_set_dns_over_tls,
925                                 SD_BUS_VTABLE_UNPRIVILEGED),
926         SD_BUS_METHOD_WITH_ARGS("SetDNSSEC",
927                                 SD_BUS_ARGS("s", mode),
928                                 SD_BUS_NO_RESULT,
929                                 bus_link_method_set_dnssec,
930                                 SD_BUS_VTABLE_UNPRIVILEGED),
931         SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors",
932                                 SD_BUS_ARGS("as", names),
933                                 SD_BUS_NO_RESULT,
934                                 bus_link_method_set_dnssec_negative_trust_anchors,
935                                 SD_BUS_VTABLE_UNPRIVILEGED),
936         SD_BUS_METHOD_WITH_ARGS("Revert",
937                                 SD_BUS_NO_ARGS,
938                                 SD_BUS_NO_RESULT,
939                                 bus_link_method_revert,
940                                 SD_BUS_VTABLE_UNPRIVILEGED),
941 
942         SD_BUS_VTABLE_END
943 };
944 
945 const BusObjectImplementation link_object = {
946         "/org/freedesktop/resolve1/link",
947         "org.freedesktop.resolve1.Link",
948         .fallback_vtables = BUS_FALLBACK_VTABLES({link_vtable, link_object_find}),
949         .node_enumerator = link_node_enumerator,
950 };
951