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