X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;ds=sidebyside;f=src%2Flibsystemd-bus%2Fsd-bus.c;h=73774ba308c67430160892ab17bf4f7931426a87;hb=2571ead1a6d2747f85ecbc980285a22421e76e21;hp=6a6d43fac0a03dd01eac4f38faf6527345601804;hpb=d728d708c3ccfcb34f6d7673f7855fbf0c10aeec;p=elogind.git diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c index 6a6d43fac..73774ba30 100644 --- a/src/libsystemd-bus/sd-bus.c +++ b/src/libsystemd-bus/sd-bus.c @@ -29,13 +29,13 @@ #include "util.h" #include "macro.h" +#include "missing.h" #include "sd-bus.h" #include "bus-internal.h" #include "bus-message.h" #include "bus-type.h" -static int ensure_running(sd_bus *bus); static int bus_poll(sd_bus *bus, bool need_more, uint64_t timeout_usec); static void bus_free(sd_bus *b) { @@ -104,16 +104,19 @@ static int hello_callback(sd_bus *bus, int error, sd_bus_message *reply, void *u assert(reply); - bus->state = BUS_RUNNING; - r = sd_bus_message_read(reply, "s", &s); if (r < 0) return r; + if (!service_name_is_valid(s) || s[0] != ':') + return -EBADMSG; + bus->unique_name = strdup(s); if (!bus->unique_name) return -ENOMEM; + bus->state = BUS_RUNNING; + return 1; } @@ -528,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"; @@ -576,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); @@ -586,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; + } } } @@ -726,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) { @@ -786,7 +829,7 @@ int sd_bus_can_send(sd_bus *bus, char type) { return -EINVAL; if (type == SD_BUS_TYPE_UNIX_FD) { - r = ensure_running(bus); + r = bus_ensure_running(bus); if (r < 0) return r; @@ -804,7 +847,7 @@ int sd_bus_get_peer(sd_bus *bus, sd_id128_t *peer) { if (!peer) return -EINVAL; - r = ensure_running(bus); + r = bus_ensure_running(bus); if (r < 0) return r; @@ -928,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; @@ -948,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); @@ -973,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) @@ -1032,7 +1105,7 @@ static int dispatch_wqueue(sd_bus *bus) { } static int dispatch_rqueue(sd_bus *bus, sd_bus_message **m) { - sd_bus_message *z; + sd_bus_message *z = NULL; int r, ret = 0; assert(bus); @@ -1249,7 +1322,7 @@ int sd_bus_send_with_reply_cancel(sd_bus *bus, uint64_t serial) { return 1; } -static int ensure_running(sd_bus *bus) { +int bus_ensure_running(sd_bus *bus) { int r; assert(bus); @@ -1297,7 +1370,7 @@ int sd_bus_send_with_reply_and_block( if (bus_error_is_dirty(error)) return -EINVAL; - r = ensure_running(bus); + r = bus_ensure_running(bus); if (r < 0) return r; @@ -1744,7 +1817,7 @@ int sd_bus_flush(sd_bus *bus) { if (bus->fd < 0) return -ENOTCONN; - r = ensure_running(bus); + r = bus_ensure_running(bus); if (r < 0) return r;