chiark / gitweb /
systemd-run: support -t mode when combined with -M
[elogind.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-common-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(NULL, 0, AF_UNSPEC, &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 r;
323
324         if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
325                 return -errno;
326
327         child = fork();
328         if (child < 0)
329                 return -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, false);
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 -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 r;
365
366         r = wait_for_terminate(child, &si);
367         if (r < 0)
368                 return r;
369         if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
370                 return -EIO;
371
372         r = sd_bus_message_new_method_return(message, &reply);
373         if (r < 0)
374                 return r;
375
376         r = sd_bus_message_open_container(reply, 'a', "{ss}");
377         if (r < 0)
378                 return 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 r;
384         }
385
386         r = sd_bus_message_close_container(reply);
387         if (r < 0)
388                 return r;
389
390         return sd_bus_send(bus, reply, NULL);
391 }
392
393 int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
394         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
395         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
396         _cleanup_close_pair_ int pair[2] = { -1, -1 };
397         _cleanup_close_ int master = -1;
398         union {
399                 struct cmsghdr cmsghdr;
400                 uint8_t buf[CMSG_SPACE(sizeof(int))];
401         } control = {};
402         struct msghdr mh = {
403                 .msg_control = &control,
404                 .msg_controllen = sizeof(control),
405         };
406         Machine *m = userdata;
407         _cleanup_free_ char *pty_name = NULL;
408         struct cmsghdr *cmsg;
409         siginfo_t si;
410         pid_t child;
411         int r;
412
413         assert(bus);
414         assert(message);
415         assert(m);
416
417         r = namespace_open(m->leader, &pidnsfd, &mntnsfd, NULL, &rootfd);
418         if (r < 0)
419                 return r;
420
421         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
422                 return -errno;
423
424         child = fork();
425         if (child < 0)
426                 return -errno;
427
428         if (child == 0) {
429                 pair[0] = safe_close(pair[0]);
430
431                 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
432                 if (r < 0)
433                         _exit(EXIT_FAILURE);
434
435                 master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC);
436                 if (master < 0)
437                         _exit(EXIT_FAILURE);
438
439                 cmsg = CMSG_FIRSTHDR(&mh);
440                 cmsg->cmsg_level = SOL_SOCKET;
441                 cmsg->cmsg_type = SCM_RIGHTS;
442                 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
443                 memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
444
445                 mh.msg_controllen = cmsg->cmsg_len;
446
447                 if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
448                         _exit(EXIT_FAILURE);
449
450                 _exit(EXIT_SUCCESS);
451         }
452
453         pair[1] = safe_close(pair[1]);
454
455         r = wait_for_terminate(child, &si);
456         if (r < 0)
457                 return r;
458         if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
459                 return -EIO;
460
461         if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
462                 return -errno;
463
464         for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
465                 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
466                         int *fds;
467                         unsigned n_fds;
468
469                         fds = (int*) CMSG_DATA(cmsg);
470                         n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
471
472                         if (n_fds != 1) {
473                                 close_many(fds, n_fds);
474                                 return -EIO;
475                         }
476
477                         master = fds[0];
478                 }
479
480         if (master < 0)
481                 return -EIO;
482
483         r = ptsname_malloc(master, &pty_name);
484         if (r < 0)
485                 return r;
486
487         r = sd_bus_message_new_method_return(message, &reply);
488         if (r < 0)
489                 return r;
490
491         r = sd_bus_message_append(reply, "hs", master, pty_name);
492         if (r < 0)
493                 return r;
494
495         return sd_bus_send(bus, reply, NULL);
496 }
497
498 const sd_bus_vtable machine_vtable[] = {
499         SD_BUS_VTABLE_START(0),
500         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
501         SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
502         BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
503         SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
504         SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
505         SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
506         SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
507         SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
508         SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
509         SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
510         SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
511         SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
512         SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
513         SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
514         SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
515         SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
516         SD_BUS_VTABLE_END
517 };
518
519 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
520         Manager *m = userdata;
521         Machine *machine;
522         int r;
523
524         assert(bus);
525         assert(path);
526         assert(interface);
527         assert(found);
528         assert(m);
529
530         if (streq(path, "/org/freedesktop/machine1/machine/self")) {
531                 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
532                 sd_bus_message *message;
533                 pid_t pid;
534
535                 message = sd_bus_get_current_message(bus);
536                 if (!message)
537                         return 0;
538
539                 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
540                 if (r < 0)
541                         return r;
542
543                 r = sd_bus_creds_get_pid(creds, &pid);
544                 if (r < 0)
545                         return r;
546
547                 r = manager_get_machine_by_pid(m, pid, &machine);
548                 if (r <= 0)
549                         return 0;
550         } else {
551                 _cleanup_free_ char *e = NULL;
552                 const char *p;
553
554                 p = startswith(path, "/org/freedesktop/machine1/machine/");
555                 if (!p)
556                         return 0;
557
558                 e = bus_label_unescape(p);
559                 if (!e)
560                         return -ENOMEM;
561
562                 machine = hashmap_get(m->machines, e);
563                 if (!machine)
564                         return 0;
565         }
566
567         *found = machine;
568         return 1;
569 }
570
571 char *machine_bus_path(Machine *m) {
572         _cleanup_free_ char *e = NULL;
573
574         assert(m);
575
576         e = bus_label_escape(m->name);
577         if (!e)
578                 return NULL;
579
580         return strappend("/org/freedesktop/machine1/machine/", e);
581 }
582
583 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
584         _cleanup_strv_free_ char **l = NULL;
585         Machine *machine = NULL;
586         Manager *m = userdata;
587         Iterator i;
588         int r;
589
590         assert(bus);
591         assert(path);
592         assert(nodes);
593
594         HASHMAP_FOREACH(machine, m->machines, i) {
595                 char *p;
596
597                 p = machine_bus_path(machine);
598                 if (!p)
599                         return -ENOMEM;
600
601                 r = strv_consume(&l, p);
602                 if (r < 0)
603                         return r;
604         }
605
606         *nodes = l;
607         l = NULL;
608
609         return 1;
610 }
611
612 int machine_send_signal(Machine *m, bool new_machine) {
613         _cleanup_free_ char *p = NULL;
614
615         assert(m);
616
617         p = machine_bus_path(m);
618         if (!p)
619                 return -ENOMEM;
620
621         return sd_bus_emit_signal(
622                         m->manager->bus,
623                         "/org/freedesktop/machine1",
624                         "org.freedesktop.machine1.Manager",
625                         new_machine ? "MachineNew" : "MachineRemoved",
626                         "so", m->name, p);
627 }
628
629 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
630         _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
631         _cleanup_free_ char *p = NULL;
632
633         assert(m);
634
635         if (!m->create_message)
636                 return 0;
637
638         c = m->create_message;
639         m->create_message = NULL;
640
641         if (error)
642                 return sd_bus_reply_method_error(c, error);
643
644         /* Update the machine state file before we notify the client
645          * about the result. */
646         machine_save(m);
647
648         p = machine_bus_path(m);
649         if (!p)
650                 return -ENOMEM;
651
652         return sd_bus_reply_method_return(c, "o", p);
653 }