diff options
author | Lennart Poettering <lennart@poettering.net> | 2013-03-22 03:36:58 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2013-03-22 03:37:10 +0100 |
commit | 2571ead1a6d2747f85ecbc980285a22421e76e21 (patch) | |
tree | 8ad509c7e60f634da1f549583e0446be36d01c26 /src | |
parent | 20902f3ec8b9d3f8949b15dbd961d3eeb37e9b7b (diff) |
bus: implicitly collect ucred/label information
Diffstat (limited to 'src')
-rw-r--r-- | src/libsystemd-bus/bus-internal.h | 4 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-message.c | 37 | ||||
-rw-r--r-- | src/libsystemd-bus/bus-message.h | 5 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.c | 97 | ||||
-rw-r--r-- | src/libsystemd-bus/sd-bus.h | 1 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-chat.c | 4 | ||||
-rw-r--r-- | src/libsystemd-bus/test-bus-marshal.c | 2 |
7 files changed, 131 insertions, 19 deletions
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h index c5bd3788b4..56514aebbc 100644 --- a/src/libsystemd-bus/bus-internal.h +++ b/src/libsystemd-bus/bus-internal.h @@ -62,6 +62,7 @@ struct sd_bus { int message_version; bool can_fds:1; bool sent_hello:1; + bool ucred_valid:1; void *rbuffer; size_t rbuffer_size; @@ -101,6 +102,9 @@ struct sd_bus { size_t auth_size; char *auth_uid; usec_t auth_timeout; + + struct ucred ucred; + char label[NAME_MAX]; }; static inline void bus_unrefp(sd_bus **b) { diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 74ea71ec0d..01213e31ad 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -224,10 +224,16 @@ static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x) return 0; } -int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) { +int bus_message_from_malloc( + void *buffer, + size_t length, + struct ucred *ucred, + const char *label, + sd_bus_message **ret) { + sd_bus_message *m; struct bus_header *h; - size_t total, fs, bs; + size_t total, fs, bs, label_sz, a; int r; assert(buffer || length <= 0); @@ -259,7 +265,13 @@ int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) { if (length != total) return -EBADMSG; - m = new0(sd_bus_message, 1); + if (label) { + label_sz = strlen(label); + a = ALIGN(sizeof(sd_bus_message)) + label_sz + 1; + } else + a = sizeof(sd_bus_message); + + m = malloc0(a); if (!m) return -ENOMEM; @@ -270,6 +282,18 @@ int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret) { m->body = (uint8_t*) buffer + sizeof(struct bus_header) + ALIGN_TO(fs, 8); m->sealed = true; + if (ucred) { + m->uid = ucred->uid; + m->pid = ucred->pid; + m->gid = ucred->gid; + m->uid_valid = m->gid_valid = true; + } + + if (label) { + m->label = (char*) m + ALIGN(sizeof(sd_bus_message)); + memcpy(m->label, label, label_sz + 1); + } + m->n_iovec = 1; m->iovec[0].iov_base = buffer; m->iovec[0].iov_len = length; @@ -629,6 +653,13 @@ int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid) { return 0; } +const char *sd_bus_message_get_label(sd_bus_message *m) { + if (!m) + return NULL; + + return m->label; +} + int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member) { if (!m) return -EINVAL; diff --git a/src/libsystemd-bus/bus-message.h b/src/libsystemd-bus/bus-message.h index ed1a4b87b1..b21fdf0ada 100644 --- a/src/libsystemd-bus/bus-message.h +++ b/src/libsystemd-bus/bus-message.h @@ -23,6 +23,7 @@ #include <stdbool.h> #include <byteswap.h> +#include <sys/socket.h> #include "macro.h" #include "sd-bus.h" @@ -77,6 +78,8 @@ struct sd_bus_message { void *fields; void *body; + char *label; + size_t rindex; uint32_t n_fds; @@ -127,5 +130,5 @@ static inline void bus_message_unrefp(sd_bus_message **m) { int bus_message_seal(sd_bus_message *m, uint64_t serial); int bus_message_dump(sd_bus_message *m); int bus_message_get_blob(sd_bus_message *m, void **buffer, size_t *sz); -int bus_message_from_malloc(void *buffer, size_t length, sd_bus_message **ret); +int bus_message_from_malloc(void *buffer, size_t length, struct ucred *ucred, const char *label, sd_bus_message **ret); int bus_message_read_strv_extend(sd_bus_message *m, char ***l); 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) diff --git a/src/libsystemd-bus/sd-bus.h b/src/libsystemd-bus/sd-bus.h index 60f2913d69..73710d1511 100644 --- a/src/libsystemd-bus/sd-bus.h +++ b/src/libsystemd-bus/sd-bus.h @@ -106,6 +106,7 @@ int sd_bus_message_get_uid(sd_bus_message *m, uid_t *uid); int sd_bus_message_get_gid(sd_bus_message *m, gid_t *gid); int sd_bus_message_get_pid(sd_bus_message *m, pid_t *pid); int sd_bus_message_get_tid(sd_bus_message *m, pid_t *tid); +const char *sd_bus_message_get_label(sd_bus_message *m); int sd_bus_message_is_signal(sd_bus_message *m, const char *interface, const char *member); int sd_bus_message_is_method_call(sd_bus_message *m, const char *interface, const char *member); diff --git a/src/libsystemd-bus/test-bus-chat.c b/src/libsystemd-bus/test-bus-chat.c index 24a194327e..23b00c7201 100644 --- a/src/libsystemd-bus/test-bus-chat.c +++ b/src/libsystemd-bus/test-bus-chat.c @@ -83,6 +83,7 @@ static int server(sd_bus *bus) { while (!client1_gone || !client2_gone) { _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL; + pid_t pid = 0; r = sd_bus_process(bus, &m); if (r < 0) { @@ -103,7 +104,8 @@ static int server(sd_bus *bus) { if (!m) continue; - log_info("Got message! %s", strna(sd_bus_message_get_member(m))); + sd_bus_message_get_pid(m, &pid); + log_info("Got message! member=%s pid=%lu label=%s", strna(sd_bus_message_get_member(m)), (unsigned long) pid, strna(sd_bus_message_get_label(m))); /* bus_message_dump(m); */ /* sd_bus_message_rewind(m, true); */ diff --git a/src/libsystemd-bus/test-bus-marshal.c b/src/libsystemd-bus/test-bus-marshal.c index d12c847f35..32bf44fffe 100644 --- a/src/libsystemd-bus/test-bus-marshal.c +++ b/src/libsystemd-bus/test-bus-marshal.c @@ -121,7 +121,7 @@ int main(int argc, char *argv[]) { m = sd_bus_message_unref(m); - r = bus_message_from_malloc(buffer, sz, &m); + r = bus_message_from_malloc(buffer, sz, NULL, NULL, &m); assert_se(r >= 0); bus_message_dump(m); |