]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine-dbus.c
change type for address family to "int"
[thirdparty/systemd.git] / src / machine / machine-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 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 <errno.h>
23 #include <string.h>
24 #include <sys/capability.h>
25 #include <arpa/inet.h>
26
27 #include "bus-util.h"
28 #include "bus-label.h"
29 #include "strv.h"
30 #include "bus-errors.h"
31 #include "copy.h"
32 #include "fileio.h"
33 #include "in-addr-util.h"
34 #include "local-addresses.h"
35 #include "machine.h"
36
37 static int property_get_id(
38 sd_bus *bus,
39 const char *path,
40 const char *interface,
41 const char *property,
42 sd_bus_message *reply,
43 void *userdata,
44 sd_bus_error *error) {
45
46 Machine *m = userdata;
47 int r;
48
49 assert(bus);
50 assert(reply);
51 assert(m);
52
53 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
54 if (r < 0)
55 return r;
56
57 return 1;
58 }
59
60 static int property_get_state(
61 sd_bus *bus,
62 const char *path,
63 const char *interface,
64 const char *property,
65 sd_bus_message *reply,
66 void *userdata,
67 sd_bus_error *error) {
68
69 Machine *m = userdata;
70 const char *state;
71 int r;
72
73 assert(bus);
74 assert(reply);
75 assert(m);
76
77 state = machine_state_to_string(machine_get_state(m));
78
79 r = sd_bus_message_append_basic(reply, 's', state);
80 if (r < 0)
81 return r;
82
83 return 1;
84 }
85
86 static int property_get_netif(
87 sd_bus *bus,
88 const char *path,
89 const char *interface,
90 const char *property,
91 sd_bus_message *reply,
92 void *userdata,
93 sd_bus_error *error) {
94
95 Machine *m = userdata;
96 int r;
97
98 assert(bus);
99 assert(reply);
100 assert(m);
101
102 assert_cc(sizeof(int) == sizeof(int32_t));
103
104 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
105 if (r < 0)
106 return r;
107
108 return 1;
109 }
110
111 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
112
113 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
114 Machine *m = userdata;
115 int r;
116
117 assert(bus);
118 assert(message);
119 assert(m);
120
121 r = machine_stop(m);
122 if (r < 0)
123 return r;
124
125 return sd_bus_reply_method_return(message, NULL);
126 }
127
128 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
129 Machine *m = userdata;
130 const char *swho;
131 int32_t signo;
132 KillWho who;
133 int r;
134
135 assert(bus);
136 assert(message);
137 assert(m);
138
139 r = sd_bus_message_read(message, "si", &swho, &signo);
140 if (r < 0)
141 return r;
142
143 if (isempty(swho))
144 who = KILL_ALL;
145 else {
146 who = kill_who_from_string(swho);
147 if (who < 0)
148 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
149 }
150
151 if (signo <= 0 || signo >= _NSIG)
152 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
153
154 r = machine_kill(m, who, signo);
155 if (r < 0)
156 return r;
157
158 return sd_bus_reply_method_return(message, NULL);
159 }
160
161 int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
162 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
163 _cleanup_close_pair_ int pair[2] = { -1, -1 };
164 _cleanup_free_ char *us = NULL, *them = NULL;
165 _cleanup_close_ int netns_fd = -1;
166 Machine *m = userdata;
167 const char *p;
168 siginfo_t si;
169 pid_t child;
170 int r;
171
172 assert(bus);
173 assert(message);
174 assert(m);
175
176 r = readlink_malloc("/proc/self/ns/net", &us);
177 if (r < 0)
178 return sd_bus_error_set_errno(error, r);
179
180 p = procfs_file_alloca(m->leader, "ns/net");
181 r = readlink_malloc(p, &them);
182 if (r < 0)
183 return sd_bus_error_set_errno(error, r);
184
185 if (streq(us, them))
186 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
187
188 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
189 if (r < 0)
190 return sd_bus_error_set_errno(error, r);
191
192 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
193 return sd_bus_error_set_errno(error, -errno);
194
195 child = fork();
196 if (child < 0)
197 return sd_bus_error_set_errno(error, -errno);
198
199 if (child == 0) {
200 _cleanup_free_ struct local_address *addresses = NULL;
201 struct local_address *a;
202 int i, n;
203
204 pair[0] = safe_close(pair[0]);
205
206 r = namespace_enter(-1, -1, netns_fd, -1);
207 if (r < 0)
208 _exit(EXIT_FAILURE);
209
210 n = local_addresses(&addresses);
211 if (n < 0)
212 _exit(EXIT_FAILURE);
213
214 for (a = addresses, i = 0; i < n; a++, i++) {
215 struct iovec iov[2] = {
216 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
217 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
218 };
219
220 r = writev(pair[1], iov, 2);
221 if (r < 0)
222 _exit(EXIT_FAILURE);
223 }
224
225 pair[1] = safe_close(pair[1]);
226
227 _exit(EXIT_SUCCESS);
228 }
229
230 pair[1] = safe_close(pair[1]);
231
232 r = sd_bus_message_new_method_return(message, &reply);
233 if (r < 0)
234 return sd_bus_error_set_errno(error, r);
235
236 r = sd_bus_message_open_container(reply, 'a', "(iay)");
237 if (r < 0)
238 return sd_bus_error_set_errno(error, r);
239
240 for (;;) {
241 int family;
242 ssize_t n;
243 union in_addr_union in_addr;
244 struct iovec iov[2];
245 struct msghdr mh = {
246 .msg_iov = iov,
247 .msg_iovlen = 2,
248 };
249
250 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
251 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
252
253 n = recvmsg(pair[0], &mh, 0);
254 if (n < 0)
255 return sd_bus_error_set_errno(error, -errno);
256 if ((size_t) n < sizeof(family))
257 break;
258
259 r = sd_bus_message_open_container(reply, 'r', "iay");
260 if (r < 0)
261 return sd_bus_error_set_errno(error, r);
262
263 r = sd_bus_message_append(reply, "i", family);
264 if (r < 0)
265 return sd_bus_error_set_errno(error, r);
266
267 switch (family) {
268
269 case AF_INET:
270 if (n != sizeof(struct in_addr) + sizeof(family))
271 return sd_bus_error_set_errno(error, EIO);
272
273 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
274 break;
275
276 case AF_INET6:
277 if (n != sizeof(struct in6_addr) + sizeof(family))
278 return sd_bus_error_set_errno(error, EIO);
279
280 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
281 break;
282 }
283 if (r < 0)
284 return sd_bus_error_set_errno(error, r);
285
286 r = sd_bus_message_close_container(reply);
287 if (r < 0)
288 return sd_bus_error_set_errno(error, r);
289 }
290
291 r = wait_for_terminate(child, &si);
292 if (r < 0)
293 return sd_bus_error_set_errno(error, r);
294 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
295 return sd_bus_error_set_errno(error, EIO);
296
297 r = sd_bus_message_close_container(reply);
298 if (r < 0)
299 return sd_bus_error_set_errno(error, r);
300
301 return sd_bus_send(bus, reply, NULL);
302 }
303
304 int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
305 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
306 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
307 _cleanup_close_pair_ int pair[2] = { -1, -1 };
308 _cleanup_strv_free_ char **l = NULL;
309 _cleanup_fclose_ FILE *f = NULL;
310 Machine *m = userdata;
311 char **k, **v;
312 siginfo_t si;
313 pid_t child;
314 int r;
315
316 assert(bus);
317 assert(message);
318 assert(m);
319
320 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
321 if (r < 0)
322 return sd_bus_error_set_errno(error, r);
323
324 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
325 return sd_bus_error_set_errno(error, -errno);
326
327 child = fork();
328 if (child < 0)
329 return sd_bus_error_set_errno(error, -errno);
330
331 if (child == 0) {
332 _cleanup_close_ int fd = -1;
333
334 pair[0] = safe_close(pair[0]);
335
336 r = namespace_enter(-1, mntns_fd, -1, root_fd);
337 if (r < 0)
338 _exit(EXIT_FAILURE);
339
340 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
341 if (fd < 0) {
342 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
343 if (fd < 0)
344 _exit(EXIT_FAILURE);
345 }
346
347 r = copy_bytes(fd, pair[1], (off_t) -1);
348 if (r < 0)
349 _exit(EXIT_FAILURE);
350
351 _exit(EXIT_SUCCESS);
352 }
353
354 pair[1] = safe_close(pair[1]);
355
356 f = fdopen(pair[0], "re");
357 if (!f)
358 return sd_bus_error_set_errno(error, -errno);
359
360 pair[0] = -1;
361
362 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
363 if (r < 0)
364 return sd_bus_error_set_errno(error, r);
365
366 r = wait_for_terminate(child, &si);
367 if (r < 0)
368 return sd_bus_error_set_errno(error, r);
369 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
370 return sd_bus_error_set_errno(error, EIO);
371
372 r = sd_bus_message_new_method_return(message, &reply);
373 if (r < 0)
374 return sd_bus_error_set_errno(error, r);
375
376 r = sd_bus_message_open_container(reply, 'a', "{ss}");
377 if (r < 0)
378 return sd_bus_error_set_errno(error, r);
379
380 STRV_FOREACH_PAIR(k, v, l) {
381 r = sd_bus_message_append(reply, "{ss}", *k, *v);
382 if (r < 0)
383 return sd_bus_error_set_errno(error, r);
384 }
385
386 r = sd_bus_message_close_container(reply);
387 if (r < 0)
388 return sd_bus_error_set_errno(error, r);
389
390 return sd_bus_send(bus, reply, NULL);
391 }
392
393 const sd_bus_vtable machine_vtable[] = {
394 SD_BUS_VTABLE_START(0),
395 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
396 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
397 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
398 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
399 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
400 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
401 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
402 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
403 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
404 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
405 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
406 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
407 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
408 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
409 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
410 SD_BUS_VTABLE_END
411 };
412
413 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
414 Manager *m = userdata;
415 Machine *machine;
416 int r;
417
418 assert(bus);
419 assert(path);
420 assert(interface);
421 assert(found);
422 assert(m);
423
424 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
425 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
426 sd_bus_message *message;
427 pid_t pid;
428
429 message = sd_bus_get_current_message(bus);
430 if (!message)
431 return 0;
432
433 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
434 if (r < 0)
435 return r;
436
437 r = sd_bus_creds_get_pid(creds, &pid);
438 if (r < 0)
439 return r;
440
441 r = manager_get_machine_by_pid(m, pid, &machine);
442 if (r <= 0)
443 return 0;
444 } else {
445 _cleanup_free_ char *e = NULL;
446 const char *p;
447
448 p = startswith(path, "/org/freedesktop/machine1/machine/");
449 if (!p)
450 return 0;
451
452 e = bus_label_unescape(p);
453 if (!e)
454 return -ENOMEM;
455
456 machine = hashmap_get(m->machines, e);
457 if (!machine)
458 return 0;
459 }
460
461 *found = machine;
462 return 1;
463 }
464
465 char *machine_bus_path(Machine *m) {
466 _cleanup_free_ char *e = NULL;
467
468 assert(m);
469
470 e = bus_label_escape(m->name);
471 if (!e)
472 return NULL;
473
474 return strappend("/org/freedesktop/machine1/machine/", e);
475 }
476
477 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
478 _cleanup_strv_free_ char **l = NULL;
479 Machine *machine = NULL;
480 Manager *m = userdata;
481 Iterator i;
482 int r;
483
484 assert(bus);
485 assert(path);
486 assert(nodes);
487
488 HASHMAP_FOREACH(machine, m->machines, i) {
489 char *p;
490
491 p = machine_bus_path(machine);
492 if (!p)
493 return -ENOMEM;
494
495 r = strv_consume(&l, p);
496 if (r < 0)
497 return r;
498 }
499
500 *nodes = l;
501 l = NULL;
502
503 return 1;
504 }
505
506 int machine_send_signal(Machine *m, bool new_machine) {
507 _cleanup_free_ char *p = NULL;
508
509 assert(m);
510
511 p = machine_bus_path(m);
512 if (!p)
513 return -ENOMEM;
514
515 return sd_bus_emit_signal(
516 m->manager->bus,
517 "/org/freedesktop/machine1",
518 "org.freedesktop.machine1.Manager",
519 new_machine ? "MachineNew" : "MachineRemoved",
520 "so", m->name, p);
521 }
522
523 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
524 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
525 _cleanup_free_ char *p = NULL;
526
527 assert(m);
528
529 if (!m->create_message)
530 return 0;
531
532 c = m->create_message;
533 m->create_message = NULL;
534
535 if (error)
536 return sd_bus_reply_method_error(c, error);
537
538 /* Update the machine state file before we notify the client
539 * about the result. */
540 machine_save(m);
541
542 p = machine_bus_path(m);
543 if (!p)
544 return -ENOMEM;
545
546 return sd_bus_reply_method_return(c, "o", p);
547 }