Commit 2571ead1 authored by Lennart Poettering's avatar Lennart Poettering

bus: implicitly collect ucred/label information

parent 20902f3e
......@@ -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) {
......
......@@ -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;
......
......@@ -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);
......@@ -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)
......
......@@ -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);
......
......@@ -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); */
......
......@@ -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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment