summaryrefslogtreecommitdiff
path: root/src/libsystemd-bus/sd-bus.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libsystemd-bus/sd-bus.c')
-rw-r--r--src/libsystemd-bus/sd-bus.c97
1 files changed, 84 insertions, 13 deletions
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 09ea01b951..73774ba308 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -29,6 +29,7 @@
#include "util.h"
#include "macro.h"
+#include "missing.h"
#include "sd-bus.h"
#include "bus-internal.h"
@@ -530,6 +531,24 @@ static int bus_read_auth(sd_bus *b) {
return 1;
}
+static int bus_setup_fd(sd_bus *b) {
+ int one;
+
+ assert(b);
+
+ /* Enable SO_PASSCRED + SO_PASSEC. We try this on any socket,
+ * just in case. This is actually irrelavant for */
+ one = 1;
+ setsockopt(b->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
+ setsockopt(b->fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));
+
+ /* Increase the buffers to a MB */
+ fd_inc_rcvbuf(b->fd, 1024*1024);
+ fd_inc_sndbuf(b->fd, 1024*1024);
+
+ return 0;
+}
+
static int bus_start_auth(sd_bus *b) {
static const char auth_prefix[] = "\0AUTH EXTERNAL ";
static const char auth_suffix[] = "\r\nNEGOTIATE_UNIX_FD\r\nBEGIN\r\n";
@@ -578,8 +597,13 @@ static int bus_start_connect(sd_bus *b) {
b->fd = socket(b->sockaddr.sa.sa_family, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
if (b->fd < 0) {
b->last_connect_error = errno;
- zero(b->sockaddr);
- continue;
+ goto try_again;
+ }
+
+ r = bus_setup_fd(b);
+ if (r < 0) {
+ b->last_connect_error = errno;
+ goto try_again;
}
r = connect(b->fd, &b->sockaddr.sa, b->sockaddr_size);
@@ -588,13 +612,18 @@ static int bus_start_connect(sd_bus *b) {
return 1;
b->last_connect_error = errno;
- close_nointr_nofail(b->fd);
- b->fd = -1;
- zero(b->sockaddr);
- continue;
+ goto try_again;
}
return bus_start_auth(b);
+
+ try_again:
+ zero(b->sockaddr);
+
+ if (b->fd >= 0) {
+ close_nointr_nofail(b->fd);
+ b->fd = -1;
+ }
}
}
@@ -728,17 +757,29 @@ int sd_bus_open_fd(int fd, sd_bus **ret) {
return -ENOMEM;
b->fd = fd;
- fd_nonblock(b->fd, true);
+
+ r = fd_nonblock(b->fd, true);
+ if (r < 0)
+ goto fail;
+
fd_cloexec(b->fd, true);
+ if (r < 0)
+ goto fail;
+
+ r = bus_setup_fd(b);
+ if (r < 0)
+ goto fail;
r = bus_start_auth(b);
- if (r < 0) {
- bus_free(b);
- return r;
- }
+ if (r < 0)
+ goto fail;
*ret = b;
return 0;
+
+fail:
+ bus_free(b);
+ return r;
}
void sd_bus_close(sd_bus *bus) {
@@ -930,7 +971,9 @@ static int message_make(sd_bus *bus, size_t size, sd_bus_message **m) {
}
}
- r = bus_message_from_malloc(bus->rbuffer, size, &t);
+ r = bus_message_from_malloc(bus->rbuffer, size,
+ bus->ucred_valid ? &bus->ucred : NULL,
+ bus->label[0] ? bus->label : NULL, &t);
if (r < 0) {
free(b);
return r;
@@ -950,6 +993,12 @@ static int message_read(sd_bus *bus, sd_bus_message **m) {
size_t need;
int r;
void *b;
+ union {
+ struct cmsghdr cmsghdr;
+ uint8_t buf[CMSG_SPACE(sizeof(struct ucred)) +
+ CMSG_SPACE(NAME_MAX)]; /*selinux label */
+ } control;
+ struct cmsghdr *cmsg;
assert(bus);
assert(m);
@@ -975,12 +1024,34 @@ static int message_read(sd_bus *bus, sd_bus_message **m) {
zero(mh);
mh.msg_iov = &iov;
mh.msg_iovlen = 1;
+ mh.msg_control = &control;
+ mh.msg_controllen = sizeof(control);
- k = recvmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL);
+ k = recvmsg(bus->fd, &mh, MSG_DONTWAIT|MSG_NOSIGNAL|MSG_CMSG_CLOEXEC);
if (k < 0)
return errno == EAGAIN ? 0 : -errno;
bus->rbuffer_size += k;
+ bus->ucred_valid = false;
+ bus->label[0] = 0;
+
+ for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg)) {
+ if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_CREDENTIALS &&
+ cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+
+ memcpy(&bus->ucred, CMSG_DATA(cmsg), sizeof(struct ucred));
+ bus->ucred_valid = true;
+
+ } else if (cmsg->cmsg_level == SOL_SOCKET &&
+ cmsg->cmsg_type == SCM_SECURITY) {
+
+ size_t l;
+ l = cmsg->cmsg_len - CMSG_LEN(0);
+ memcpy(&bus->label, CMSG_DATA(cmsg), l);
+ bus->label[l] = 0;
+ }
+ }
r = message_read_need(bus, &need);
if (r < 0)