summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2013-12-24 15:03:32 +0100
committerLennart Poettering <lennart@poettering.net>2013-12-24 15:27:59 +0100
commit8a0e0ed9ddfa208e414355881acb886270039268 (patch)
tree8e5708a04e2d9b6a8444ea1c0794f600b52edd43
parent515c883021bb3331df4d40fa62c333c0647a1d82 (diff)
bus: fake client side creds in the proxy to the caller's creds
-rw-r--r--src/bus-proxyd/bus-proxyd.c62
-rw-r--r--src/libsystemd-bus/bus-internal.h5
-rw-r--r--src/libsystemd-bus/bus-kernel.c55
-rw-r--r--src/libsystemd-bus/sd-bus.c1
4 files changed, 109 insertions, 14 deletions
diff --git a/src/bus-proxyd/bus-proxyd.c b/src/bus-proxyd/bus-proxyd.c
index a425fd2fac..b87dffe0e8 100644
--- a/src/bus-proxyd/bus-proxyd.c
+++ b/src/bus-proxyd/bus-proxyd.c
@@ -358,6 +358,40 @@ static int process_hello(sd_bus *a, sd_bus *b, sd_bus_message *m, bool *got_hell
return 1;
}
+static int getpeersec(int fd, char **ret) {
+ socklen_t n = 64;
+ char *s;
+ int r;
+
+ assert(fd >= 0);
+ assert(ret);
+
+ s = new0(char, n);
+ if (!s)
+ return -ENOMEM;
+
+ r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+ if (r < 0) {
+ free(s);
+
+ if (errno != ERANGE)
+ return r;
+
+ s = new0(char, n);
+ if (!s)
+ return -ENOMEM;
+
+ r = getsockopt(fd, SOL_SOCKET, SO_PEERSEC, s, &n);
+ if (r < 0) {
+ free(s);
+ return r;
+ }
+ }
+
+ *ret = s;
+ return 0;
+}
+
int main(int argc, char *argv[]) {
_cleanup_bus_unref_ sd_bus *a = NULL, *b = NULL;
@@ -365,6 +399,8 @@ int main(int argc, char *argv[]) {
int r, in_fd, out_fd;
bool got_hello = false;
bool is_unix;
+ struct ucred ucred = {};
+ _cleanup_free_ char *peersec = NULL;
log_set_target(LOG_TARGET_JOURNAL_OR_KMSG);
log_parse_environment();
@@ -390,6 +426,20 @@ int main(int argc, char *argv[]) {
sd_is_socket(in_fd, AF_UNIX, 0, 0) > 0 &&
sd_is_socket(out_fd, AF_UNIX, 0, 0) > 0;
+ if (is_unix) {
+ socklen_t l = sizeof(ucred);
+
+ r = getsockopt(in_fd, SOL_SOCKET, SO_PEERCRED, &ucred, &l);
+ if (r < 0) {
+ r = -errno;
+ goto finish;
+ }
+
+ assert(l == sizeof(ucred));
+
+ getpeersec(in_fd, &peersec);
+ }
+
r = sd_bus_new(&a);
if (r < 0) {
log_error("Failed to allocate bus: %s", strerror(-r));
@@ -408,6 +458,18 @@ int main(int argc, char *argv[]) {
goto finish;
}
+ if (ucred.pid > 0) {
+ a->fake_creds.pid = ucred.pid;
+ a->fake_creds.uid = ucred.uid;
+ a->fake_creds.gid = ucred.gid;
+ a->fake_creds_valid = true;
+ }
+
+ if (peersec) {
+ a->fake_label = peersec;
+ peersec = NULL;
+ }
+
r = sd_bus_start(a);
if (r < 0) {
log_error("Failed to start bus client: %s", strerror(-r));
diff --git a/src/libsystemd-bus/bus-internal.h b/src/libsystemd-bus/bus-internal.h
index 7af8c1e22d..673f30eb91 100644
--- a/src/libsystemd-bus/bus-internal.h
+++ b/src/libsystemd-bus/bus-internal.h
@@ -36,6 +36,7 @@
#include "bus-error.h"
#include "bus-match.h"
#include "bus-kernel.h"
+#include "kdbus.h"
struct reply_callback {
sd_bus_message_handler_t callback;
@@ -161,6 +162,7 @@ struct sd_bus {
bool filter_callbacks_modified:1;
bool nodes_modified:1;
bool trusted:1;
+ bool fake_creds_valid:1;
int use_memfd;
@@ -259,6 +261,9 @@ struct sd_bus {
sd_bus **default_bus_ptr;
pid_t tid;
+
+ struct kdbus_creds fake_creds;
+ char *fake_label;
};
#define BUS_DEFAULT_TIMEOUT ((usec_t) (25 * USEC_PER_SEC))
diff --git a/src/libsystemd-bus/bus-kernel.c b/src/libsystemd-bus/bus-kernel.c
index e53bc51727..fb5266d44e 100644
--- a/src/libsystemd-bus/bus-kernel.c
+++ b/src/libsystemd-bus/bus-kernel.c
@@ -317,7 +317,9 @@ fail:
}
int bus_kernel_take_fd(sd_bus *b) {
- struct kdbus_cmd_hello hello;
+ struct kdbus_cmd_hello *hello;
+ struct kdbus_item *item;
+ size_t l, sz;
int r;
assert(b);
@@ -327,13 +329,38 @@ int bus_kernel_take_fd(sd_bus *b) {
b->use_memfd = 1;
- zero(hello);
- hello.size = sizeof(hello);
- hello.conn_flags = b->hello_flags;
- hello.attach_flags = b->attach_flags;
- hello.pool_size = KDBUS_POOL_SIZE;
+ sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items));
+
+ if (b->fake_creds_valid)
+ sz += ALIGN8(offsetof(struct kdbus_item, creds));
+
+ if (b->fake_label) {
+ l = strlen(b->fake_label);
+ sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
+ }
+
+ hello = alloca0(sz);
+ hello->size = sz;
+ hello->conn_flags = b->hello_flags;
+ hello->attach_flags = b->attach_flags;
+ hello->pool_size = KDBUS_POOL_SIZE;
+
+ item = hello->items;
- r = ioctl(b->input_fd, KDBUS_CMD_HELLO, &hello);
+ if (b->fake_creds_valid) {
+ item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
+ item->type = KDBUS_ITEM_CREDS;
+ item->creds = b->fake_creds;
+
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
+ if (b->fake_label) {
+ item->size = offsetof(struct kdbus_item, str) + l + 1;
+ memcpy(item->str, b->fake_label, l+1);
+ }
+
+ r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
if (r < 0)
return -errno;
@@ -347,26 +374,26 @@ int bus_kernel_take_fd(sd_bus *b) {
/* The higher 32bit of both flags fields are considered
* 'incompatible flags'. Refuse them all for now. */
- if (hello.bus_flags > 0xFFFFFFFFULL ||
- hello.conn_flags > 0xFFFFFFFFULL)
+ if (hello->bus_flags > 0xFFFFFFFFULL ||
+ hello->conn_flags > 0xFFFFFFFFULL)
return -ENOTSUP;
- if (hello.bloom_size != BLOOM_SIZE)
+ if (hello->bloom_size != BLOOM_SIZE)
return -ENOTSUP;
- if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello.id) < 0)
+ if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
return -ENOMEM;
- b->unique_id = hello.id;
+ b->unique_id = hello->id;
b->is_kernel = true;
b->bus_client = true;
- b->can_fds = !!(hello.conn_flags & KDBUS_HELLO_ACCEPT_FD);
+ b->can_fds = !!(hello->conn_flags & KDBUS_HELLO_ACCEPT_FD);
b->message_version = 2;
b->message_endian = BUS_NATIVE_ENDIAN;
/* the kernel told us the UUID of the underlying bus */
- memcpy(b->server_id.bytes, hello.id128, sizeof(b->server_id.bytes));
+ memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
return bus_start_running(b);
}
diff --git a/src/libsystemd-bus/sd-bus.c b/src/libsystemd-bus/sd-bus.c
index 9dfb6e4442..910a5f8136 100644
--- a/src/libsystemd-bus/sd-bus.c
+++ b/src/libsystemd-bus/sd-bus.c
@@ -141,6 +141,7 @@ static void bus_free(sd_bus *b) {
free(b->address);
free(b->kernel);
free(b->machine);
+ free(b->fake_label);
free(b->exec_path);
strv_free(b->exec_argv);