#include "string-table.h"
#include "strv.h"
#include "user-util.h"
+#include "varlink-io.systemd.Hostname.h"
#include "virt.h"
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
sd_event *event;
sd_bus *bus;
+ VarlinkServer *varlink_server;
Hashmap *polkit_registry;
} Context;
hashmap_free(c->polkit_registry);
sd_event_unref(c->event);
sd_bus_flush_close_unref(c->bus);
+ varlink_server_unref(c->varlink_server);
}
static void context_read_etc_hostname(Context *c) {
return sd_bus_send(NULL, reply, NULL);
}
-static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL, *text = NULL,
+static int build_describe_response(Context *c, bool privileged, JsonVariant **ret) {
+ _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL,
*chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
*firmware_vendor = NULL;
usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
sd_id128_t machine_id, boot_id, product_uuid = SD_ID128_NULL;
unsigned local_cid = VMADDR_CID_ANY;
- Context *c = ASSERT_PTR(userdata);
- bool privileged;
struct utsname u;
int r;
- assert(m);
-
- r = bus_verify_polkit_async(
- m,
- "org.freedesktop.hostname1.get-description",
- /* details= */ NULL,
- &c->polkit_registry,
- error);
- if (r == 0)
- return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
-
- /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
- * the product ID which we'll check explicitly. */
- privileged = r > 0;
+ assert(c);
+ assert(ret);
context_read_etc_hostname(c);
context_read_machine_info(c);
JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_ID128(product_uuid)),
JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_NULL),
JSON_BUILD_PAIR_CONDITION(local_cid != VMADDR_CID_ANY, "VSockCID", JSON_BUILD_UNSIGNED(local_cid))));
-
if (r < 0)
return log_error_errno(r, "Failed to build JSON data: %m");
+ *ret = TAKE_PTR(v);
+ return 0;
+}
+
+static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ Context *c = ASSERT_PTR(userdata);
+ _cleanup_free_ char *text = NULL;
+ bool privileged;
+ int r;
+
+ assert(m);
+
+ r = bus_verify_polkit_async(
+ m,
+ "org.freedesktop.hostname1.get-description",
+ /* details= */ NULL,
+ &c->polkit_registry,
+ error);
+ if (r == 0)
+ return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
+ * the product ID which we'll check explicitly. */
+ privileged = r > 0;
+
+ r = build_describe_response(c, privileged, &v);
+ if (r < 0)
+ return r;
+
r = json_variant_format(v, 0, &text);
if (r < 0)
return log_error_errno(r, "Failed to format JSON data: %m");
};
static int connect_bus(Context *c) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
assert(c);
return 0;
}
+static int vl_method_describe(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
+ static const JsonDispatch dispatch_table[] = {
+ VARLINK_DISPATCH_POLKIT_FIELD,
+ {}
+ };
+
+ Context *c = ASSERT_PTR(userdata);
+ bool privileged;
+ int r;
+
+ assert(link);
+ assert(parameters);
+
+ r = varlink_dispatch(link, parameters, dispatch_table, /* userdata= */ NULL);
+ if (r != 0)
+ return r;
+
+ r = varlink_verify_polkit_async(
+ link,
+ c->bus,
+ "org.freedesktop.hostname1.get-hardware-serial",
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ &c->polkit_registry);
+ if (r == 0)
+ return 0; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+ /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
+ * the product ID which we'll check explicitly. */
+ privileged = r > 0;
+
+ if (json_variant_elements(parameters) > 0)
+ return varlink_error_invalid_parameter(link, parameters);
+
+ _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
+ r = build_describe_response(c, privileged, &v);
+ if (r < 0)
+ return r;
+
+ return varlink_reply(link, v);
+}
+
+static int connect_varlink(Context *c) {
+ int r;
+
+ assert(c);
+ assert(c->event);
+ assert(!c->varlink_server);
+
+ r = varlink_server_new(&c->varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
+ if (r < 0)
+ return log_error_errno(r, "Failed to allocate Varlink server: %m");
+
+ varlink_server_set_userdata(c->varlink_server, c);
+
+ r = varlink_server_add_interface(c->varlink_server, &vl_interface_io_systemd_Hostname);
+ if (r < 0)
+ return log_error_errno(r, "Failed to add Hostname interface to varlink server: %m");
+
+ r = varlink_server_bind_method_many(
+ c->varlink_server,
+ "io.systemd.Hostname.Describe", vl_method_describe);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind Varlink method calls: %m");
+
+ r = varlink_server_attach_event(c->varlink_server, c->event, SD_EVENT_PRIORITY_NORMAL);
+ if (r < 0)
+ return log_error_errno(r, "Failed to attach Varlink server to event loop: %m");
+
+ r = varlink_server_listen_auto(c->varlink_server);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind to passed Varlink sockets: %m");
+ if (r == 0) {
+ r = varlink_server_listen_address(c->varlink_server, "/run/systemd/io.systemd.Hostname", 0666);
+ if (r < 0)
+ return log_error_errno(r, "Failed to bind to Varlink socket: %m");
+ }
+
+ return 0;
+}
+
static int run(int argc, char *argv[]) {
_cleanup_(context_destroy) Context context = {
.hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
if (r < 0)
return r;
+ r = connect_varlink(&context);
+ if (r < 0)
+ return r;
+
r = bus_event_loop_with_idle(
context.event,
context.bus,
--- /dev/null
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "varlink-io.systemd.Credentials.h"
+
+static VARLINK_DEFINE_METHOD(
+ Describe,
+ VARLINK_DEFINE_OUTPUT(Hostname, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(StaticHostname, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(PrettyHostname, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(DefaultHostname, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(HostnameSource, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(IconName, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(Chassis, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(Deployment, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(Location, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(KernelName, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(KernelRelease, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(KernelVersion, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(OperatingSystemPrettyName, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(OperatingSystemCPEName, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(OperatingSystemHomeURL, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(OperatingSystemSupportEnd, VARLINK_INT, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(HardwareVendor, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(HardwareModel, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(HardwareSerial, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(FirmwareVersion, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(FirmwareVendor, VARLINK_STRING, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(FirmwareDate, VARLINK_INT, VARLINK_NULLABLE),
+ VARLINK_DEFINE_OUTPUT(MachineID, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(BootID, VARLINK_STRING, 0),
+ VARLINK_DEFINE_OUTPUT(ProductUUID, VARLINK_STRING, VARLINK_NULLABLE));
+
+VARLINK_DEFINE_INTERFACE(
+ io_systemd_Hostname,
+ "io.systemd.Hostname",
+ &vl_method_Describe);