]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/libsystemd-bus/bus-container.c
run: add support for executing commands remotely via SSH or in a container
[thirdparty/systemd.git] / src / libsystemd-bus / bus-container.c
CommitLineData
a7893c6b
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 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 <unistd.h>
23#include <fcntl.h>
24
25#include "util.h"
26#include "fileio.h"
27#include "bus-internal.h"
28#include "bus-socket.h"
29#include "bus-container.h"
30
31int bus_container_connect(sd_bus *b) {
32 _cleanup_free_ char *p = NULL, *s = NULL, *ns = NULL, *root = NULL, *class = NULL;
33 _cleanup_close_ int nsfd = -1, rootfd = -1;
34 siginfo_t si;
35 pid_t leader, child;
36 int r;
37
38 assert(b);
39 assert(b->input_fd < 0);
40 assert(b->output_fd < 0);
41
42 p = strappend("/run/systemd/machines/", b->machine);
43 if (!p)
44 return -ENOMEM;
45
46 r = parse_env_file(p, NEWLINE, "LEADER", &s, "CLASS", &class, NULL);
d21ed1ea
LP
47 if (r == -ENOENT)
48 return -EHOSTDOWN;
a7893c6b
LP
49 if (r < 0)
50 return r;
51 if (!s)
52 return -EIO;
53
54 if (!streq_ptr(class, "container"))
55 return -EIO;
56
57 r = parse_pid(s, &leader);
58 if (r < 0)
59 return r;
60 if (leader <= 1)
61 return -EIO;
62
63 r = asprintf(&ns, "/proc/%lu/ns/mnt", (unsigned long) leader);
64 if (r < 0)
65 return -ENOMEM;
66
67 nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
68 if (nsfd < 0)
69 return -errno;
70
71 r = asprintf(&root, "/proc/%lu/root", (unsigned long) leader);
72 if (r < 0)
73 return -ENOMEM;
74
75 rootfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC);
76 if (rootfd < 0)
77 return -errno;
78
79 b->input_fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
80 if (b->input_fd < 0)
81 return -errno;
82
83 b->output_fd = b->input_fd;
84
85 r = bus_socket_setup(b);
86 if (r < 0)
87 return r;
88
89 child = fork();
90 if (child < 0)
91 return -errno;
92
93 if (child == 0) {
94 r = setns(nsfd, CLONE_NEWNS);
95 if (r < 0)
96 _exit(255);
97
98 if (fchdir(rootfd) < 0)
99 _exit(255);
100
101 if (chroot(".") < 0)
102 _exit(255);
103
104
105 r = connect(b->input_fd, &b->sockaddr.sa, b->sockaddr_size);
106 if (r < 0) {
107 if (errno == EINPROGRESS)
108 _exit(1);
109
110 _exit(255);
111 }
112
113 _exit(0);
114 }
115
116 r = wait_for_terminate(child, &si);
117 if (r < 0)
118 return r;
119
120 if (si.si_code != CLD_EXITED)
121 return -EIO;
122
123 if (si.si_status == 1)
124 return 1;
125
126 if (si.si_status != 0)
127 return -EIO;
128
129 return bus_socket_start_auth(b);
130}