]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-bus/bus-container.c
2 This file is part of systemd.
4 Copyright 2013 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
23 #include "bus-container.h"
24 #include "bus-internal.h"
25 #include "bus-socket.h"
27 #include "process-util.h"
30 int bus_container_connect_socket(sd_bus
*b
) {
31 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
32 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, usernsfd
= -1, rootfd
= -1;
39 assert(b
->input_fd
< 0);
40 assert(b
->output_fd
< 0);
41 assert(b
->nspid
> 0 || b
->machine
);
44 r
= container_get_leader(b
->machine
, &b
->nspid
);
49 r
= namespace_open(b
->nspid
, &pidnsfd
, &mntnsfd
, NULL
, &usernsfd
, &rootfd
);
53 b
->input_fd
= socket(b
->sockaddr
.sa
.sa_family
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
57 b
->output_fd
= b
->input_fd
;
61 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
71 pair
[0] = safe_close(pair
[0]);
73 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, usernsfd
, rootfd
);
77 /* We just changed PID namespace, however it will only
78 * take effect on the children we now fork. Hence,
79 * let's fork another time, and connect from this
80 * grandchild, so that SO_PEERCRED of our connection
81 * comes from a process from within the container, and
82 * not outside of it */
88 if (grandchild
== 0) {
90 r
= connect(b
->input_fd
, &b
->sockaddr
.sa
, b
->sockaddr_size
);
92 /* Try to send error up */
94 (void) write(pair
[1], &error_buf
, sizeof(error_buf
));
101 r
= wait_for_terminate(grandchild
, &si
);
105 if (si
.si_code
!= CLD_EXITED
)
111 pair
[1] = safe_close(pair
[1]);
113 r
= wait_for_terminate(child
, &si
);
117 n
= read(pair
[0], &error_buf
, sizeof(error_buf
));
122 if (n
!= sizeof(error_buf
))
128 if (error_buf
== EINPROGRESS
)
135 if (si
.si_code
!= CLD_EXITED
)
138 if (si
.si_status
!= EXIT_SUCCESS
)
141 return bus_socket_start_auth(b
);
144 int bus_container_connect_kernel(sd_bus
*b
) {
145 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
146 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, usernsfd
= -1, rootfd
= -1;
148 struct cmsghdr cmsghdr
;
149 uint8_t buf
[CMSG_SPACE(sizeof(int))];
153 .iov_base
= &error_buf
,
154 .iov_len
= sizeof(error_buf
),
157 .msg_control
= &control
,
158 .msg_controllen
= sizeof(control
),
162 struct cmsghdr
*cmsg
;
169 assert(b
->input_fd
< 0);
170 assert(b
->output_fd
< 0);
171 assert(b
->nspid
> 0 || b
->machine
);
174 r
= container_get_leader(b
->machine
, &b
->nspid
);
179 r
= namespace_open(b
->nspid
, &pidnsfd
, &mntnsfd
, NULL
, &usernsfd
, &rootfd
);
183 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
193 pair
[0] = safe_close(pair
[0]);
195 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, usernsfd
, rootfd
);
199 /* We just changed PID namespace, however it will only
200 * take effect on the children we now fork. Hence,
201 * let's fork another time, and connect from this
202 * grandchild, so that kdbus only sees the credentials
203 * of this process which comes from within the
204 * container, and not outside of it */
210 if (grandchild
== 0) {
211 fd
= open(b
->kernel
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
213 /* Try to send error up */
215 (void) write(pair
[1], &error_buf
, sizeof(error_buf
));
219 r
= send_one_fd(pair
[1], fd
, 0);
226 r
= wait_for_terminate(grandchild
, &si
);
230 if (si
.si_code
!= CLD_EXITED
)
236 pair
[1] = safe_close(pair
[1]);
238 r
= wait_for_terminate(child
, &si
);
242 n
= recvmsg(pair
[0], &mh
, MSG_NOSIGNAL
|MSG_CMSG_CLOEXEC
);
246 CMSG_FOREACH(cmsg
, &mh
) {
247 if (cmsg
->cmsg_level
== SOL_SOCKET
&& cmsg
->cmsg_type
== SCM_RIGHTS
) {
253 fds
= (int*) CMSG_DATA(cmsg
);
254 n_fds
= (cmsg
->cmsg_len
- CMSG_LEN(0)) / sizeof(int);
257 close_many(fds
, n_fds
);
265 /* If there's an fd passed, we are good. */
267 b
->input_fd
= b
->output_fd
= fd
;
268 return bus_kernel_take_fd(b
);
271 /* If there's an error passed, use it */
272 if (n
== sizeof(error_buf
) && error_buf
> 0)
275 /* Otherwise, we have no clue */