From 02b0d24d1e30331004ee15a4aaccc20ac1d87553 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 25 Sep 2023 16:00:00 +0200 Subject: [PATCH] varlink: add varlink_invocation() call This call checks if we are invoked in a socket-activation Varlink server context. It's useful for commands that can be run from the command line or as Varlink service and then either serve commands from the cmdline or those from Varlink. --- src/shared/varlink.c | 35 +++++++++++++++++++++++++++++++++++ src/shared/varlink.h | 10 +++++++++- 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/src/shared/varlink.c b/src/shared/varlink.c index e97127838a2..f061024785c 100644 --- a/src/shared/varlink.c +++ b/src/shared/varlink.c @@ -3540,3 +3540,38 @@ int varlink_server_deserialize_one(VarlinkServer *s, const char *value, FDSet *f LIST_PREPEND(sockets, s->sockets, TAKE_PTR(ss)); return 0; } + +int varlink_invocation(VarlinkInvocationFlags flags) { + _cleanup_strv_free_ char **names = NULL; + int r, b; + socklen_t l = sizeof(b); + + /* Returns true if this is a "pure" varlink server invocation, i.e. with one fd passed. */ + + r = sd_listen_fds_with_names(/* unset_environment= */ false, &names); + if (r < 0) + return r; + if (r == 0) + return false; + if (r > 1) + return -ETOOMANYREFS; + + if (!strv_equal(names, STRV_MAKE("varlink"))) + return false; + + if (FLAGS_SET(flags, VARLINK_ALLOW_LISTEN|VARLINK_ALLOW_ACCEPT)) /* Both flags set? Then allow everything */ + return true; + + if ((flags & (VARLINK_ALLOW_LISTEN|VARLINK_ALLOW_ACCEPT)) == 0) /* Neither is set, then fail */ + return -EISCONN; + + if (getsockopt(SD_LISTEN_FDS_START, SOL_SOCKET, SO_ACCEPTCONN, &b, &l) < 0) + return -errno; + + assert(l == sizeof(b)); + + if (!FLAGS_SET(flags, b ? VARLINK_ALLOW_LISTEN : VARLINK_ALLOW_ACCEPT)) + return -EISCONN; + + return true; +} diff --git a/src/shared/varlink.h b/src/shared/varlink.h index cfb7f7ed8be..5fe529c8532 100644 --- a/src/shared/varlink.h +++ b/src/shared/varlink.h @@ -46,7 +46,6 @@ typedef enum VarlinkServerFlags { VARLINK_SERVER_MYSELF_ONLY = 1 << 1, /* Only accessible by our own UID */ VARLINK_SERVER_ACCOUNT_UID = 1 << 2, /* Do per user accounting */ VARLINK_SERVER_INHERIT_USERDATA = 1 << 3, /* Initialize Varlink connection userdata from VarlinkServer userdata */ - _VARLINK_SERVER_FLAGS_ALL = (1 << 4) - 1, } VarlinkServerFlags; @@ -185,6 +184,15 @@ unsigned varlink_server_current_connections(VarlinkServer *s); int varlink_server_set_description(VarlinkServer *s, const char *description); +typedef enum VarlinkInvocationFlags { + VARLINK_ALLOW_LISTEN = 1 << 0, + VARLINK_ALLOW_ACCEPT = 1 << 1, + _VARLINK_SERVER_INVOCATION_FLAGS_MAX = (1 << 2) - 1, + _VARLINK_SERVER_INVOCATION_FLAGS_INVALID = -EINVAL, +} VarlinkInvocationFlags; + +int varlink_invocation(VarlinkInvocationFlags flags); + DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_close_unref); DEFINE_TRIVIAL_CLEANUP_FUNC(Varlink *, varlink_flush_close_unref);