summaryrefslogtreecommitdiffstats
path: root/src/hostname
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 03:50:40 +0000
commitfc53809803cd2bc2434e312b19a18fa36776da12 (patch)
treeb4b43bd6538f51965ce32856e9c053d0f90919c8 /src/hostname
parentAdding upstream version 255.5. (diff)
downloadsystemd-fc53809803cd2bc2434e312b19a18fa36776da12.tar.xz
systemd-fc53809803cd2bc2434e312b19a18fa36776da12.zip
Adding upstream version 256.upstream/256
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/hostname')
-rw-r--r--src/hostname/hostnamectl.c87
-rw-r--r--src/hostname/hostnamed.c415
2 files changed, 346 insertions, 156 deletions
diff --git a/src/hostname/hostnamectl.c b/src/hostname/hostnamectl.c
index 14fc160..d1c4d47 100644
--- a/src/hostname/hostnamectl.c
+++ b/src/hostname/hostnamectl.c
@@ -24,6 +24,7 @@
#include "main-func.h"
#include "parse-argument.h"
#include "pretty-print.h"
+#include "socket-util.h"
#include "spawn-polkit-agent.h"
#include "terminal-util.h"
#include "verbs.h"
@@ -58,6 +59,9 @@ typedef struct StatusInfo {
usec_t firmware_date;
sd_id128_t machine_id;
sd_id128_t boot_id;
+ const char *hardware_serial;
+ sd_id128_t product_uuid;
+ uint32_t vsock_cid;
} StatusInfo;
static const char* chassis_string_to_glyph(const char *chassis) {
@@ -191,6 +195,22 @@ static int print_status_info(StatusInfo *i) {
return table_log_add_error(r);
}
+ if (!sd_id128_is_null(i->product_uuid)) {
+ r = table_add_many(table,
+ TABLE_FIELD, "Product UUID",
+ TABLE_UUID, i->product_uuid);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
+ if (i->vsock_cid != VMADDR_CID_ANY) {
+ r = table_add_many(table,
+ TABLE_FIELD, "AF_VSOCK CID",
+ TABLE_UINT32, i->vsock_cid);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
if (!isempty(i->virtualization)) {
r = table_add_many(table,
TABLE_FIELD, "Virtualization",
@@ -216,7 +236,7 @@ static int print_status_info(StatusInfo *i) {
return table_log_add_error(r);
}
- if (i->os_support_end != USEC_INFINITY) {
+ if (timestamp_is_set(i->os_support_end)) {
usec_t n = now(CLOCK_REALTIME);
r = table_add_many(table,
@@ -264,6 +284,14 @@ static int print_status_info(StatusInfo *i) {
return table_log_add_error(r);
}
+ if (!isempty(i->hardware_serial)) {
+ r = table_add_many(table,
+ TABLE_FIELD, "Hardware Serial",
+ TABLE_STRING, i->hardware_serial);
+ if (r < 0)
+ return table_log_add_error(r);
+ }
+
if (!isempty(i->firmware_version)) {
r = table_add_many(table,
TABLE_FIELD, "Firmware Version",
@@ -332,7 +360,11 @@ static int get_one_name(sd_bus *bus, const char* attr, char **ret) {
}
static int show_all_names(sd_bus *bus) {
- StatusInfo info = {};
+ StatusInfo info = {
+ .vsock_cid = VMADDR_CID_ANY,
+ .os_support_end = USEC_INFINITY,
+ .firmware_date = USEC_INFINITY,
+ };
static const struct bus_properties_map hostname_map[] = {
{ "Hostname", "s", NULL, offsetof(StatusInfo, hostname) },
@@ -354,6 +386,7 @@ static int show_all_names(sd_bus *bus) {
{ "FirmwareDate", "t", NULL, offsetof(StatusInfo, firmware_date) },
{ "MachineID", "ay", bus_map_id128, offsetof(StatusInfo, machine_id) },
{ "BootID", "ay", bus_map_id128, offsetof(StatusInfo, boot_id) },
+ { "VSockCID", "u", NULL, offsetof(StatusInfo, vsock_cid) },
{}
}, manager_map[] = {
{ "Virtualization", "s", NULL, offsetof(StatusInfo, virtualization) },
@@ -387,6 +420,49 @@ static int show_all_names(sd_bus *bus) {
if (r < 0)
return log_error_errno(r, "Failed to query system properties: %s", bus_error_message(&error, r));
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *product_uuid_reply = NULL;
+ r = bus_call_method(bus,
+ bus_hostname,
+ "GetProductUUID",
+ &error,
+ &product_uuid_reply,
+ "b",
+ false);
+ if (r < 0) {
+ log_full_errno(sd_bus_error_has_names(
+ &error,
+ BUS_ERROR_NO_PRODUCT_UUID,
+ SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED,
+ SD_BUS_ERROR_UNKNOWN_METHOD) ? LOG_DEBUG : LOG_WARNING,
+ r, "Failed to query product UUID, ignoring: %s", bus_error_message(&error, r));
+ sd_bus_error_free(&error);
+ } else {
+ r = bus_message_read_id128(product_uuid_reply, &info.product_uuid);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *hardware_serial_reply = NULL;
+ r = bus_call_method(bus,
+ bus_hostname,
+ "GetHardwareSerial",
+ &error,
+ &hardware_serial_reply,
+ NULL);
+ if (r < 0)
+ log_full_errno(sd_bus_error_has_names(
+ &error,
+ BUS_ERROR_NO_HARDWARE_SERIAL,
+ SD_BUS_ERROR_INTERACTIVE_AUTHORIZATION_REQUIRED,
+ SD_BUS_ERROR_UNKNOWN_METHOD) ||
+ ERRNO_IS_DEVICE_ABSENT(r) ? LOG_DEBUG : LOG_WARNING, /* old hostnamed used to send ENOENT/ENODEV back to client as is, handle that gracefully */
+ r, "Failed to query hardware serial, ignoring: %s", bus_error_message(&error, r));
+ else {
+ r = sd_bus_message_read_basic(hardware_serial_reply, 's', &info.hardware_serial);
+ if (r < 0)
+ return bus_log_parse_error(r);
+ }
+
/* For older version of hostnamed. */
if (!arg_host) {
if (sd_id128_is_null(info.machine_id))
@@ -603,6 +679,7 @@ static int help(void) {
" --pretty Only set pretty hostname\n"
" --json=pretty|short|off\n"
" Generate JSON output\n"
+ " -j Same as --json=pretty on tty, --json=short otherwise\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
@@ -645,7 +722,7 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "hH:M:", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "hH:M:j", options, NULL)) >= 0)
switch (c) {
@@ -688,6 +765,10 @@ static int parse_argv(int argc, char *argv[]) {
break;
+ case 'j':
+ arg_json_format_flags = JSON_FORMAT_PRETTY_AUTO|JSON_FORMAT_COLOR_AUTO;
+ break;
+
case '?':
return -EINVAL;
diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c
index fc7a97f..82d0880 100644
--- a/src/hostname/hostnamed.c
+++ b/src/hostname/hostnamed.c
@@ -6,12 +6,15 @@
#include <sys/types.h>
#include <unistd.h>
+#include "sd-device.h"
+
#include "alloc-util.h"
#include "bus-common-errors.h"
#include "bus-get-properties.h"
#include "bus-log-control-api.h"
#include "bus-polkit.h"
#include "constants.h"
+#include "daemon-util.h"
#include "env-file-label.h"
#include "env-file.h"
#include "env-util.h"
@@ -28,14 +31,16 @@
#include "os-util.h"
#include "parse-util.h"
#include "path-util.h"
-#include "sd-device.h"
#include "selinux-util.h"
#include "service-util.h"
#include "signal-util.h"
+#include "socket-util.h"
#include "stat-util.h"
#include "string-table.h"
#include "strv.h"
#include "user-util.h"
+#include "utf8.h"
+#include "varlink-io.systemd.Hostname.h"
#include "virt.h"
#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
@@ -73,6 +78,9 @@ typedef struct Context {
struct stat etc_os_release_stat;
struct stat etc_machine_info_stat;
+ sd_event *event;
+ sd_bus *bus;
+ VarlinkServer *varlink_server;
Hashmap *polkit_registry;
} Context;
@@ -91,7 +99,10 @@ static void context_destroy(Context *c) {
assert(c);
context_reset(c, UINT64_MAX);
- bus_verify_polkit_async_registry_free(c->polkit_registry);
+ 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) {
@@ -200,7 +211,6 @@ static bool use_dmi_data(void) {
static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
- _cleanup_free_ char *b = NULL;
const char *s = NULL;
int r;
@@ -216,17 +226,7 @@ static int get_dmi_data(const char *database_key, const char *regular_key, char
if (!s && regular_key)
(void) sd_device_get_property_value(device, regular_key, &s);
- if (!ret)
- return !!s;
-
- if (s) {
- b = strdup(s);
- if (!b)
- return -ENOMEM;
- }
-
- *ret = TAKE_PTR(b);
- return !!s;
+ return strdup_to_full(ret, s);
}
static int get_hardware_vendor(char **ret) {
@@ -239,7 +239,6 @@ static int get_hardware_model(char **ret) {
static int get_hardware_firmware_data(const char *sysattr, char **ret) {
_cleanup_(sd_device_unrefp) sd_device *device = NULL;
- _cleanup_free_ char *b = NULL;
const char *s = NULL;
int r;
@@ -253,94 +252,105 @@ static int get_hardware_firmware_data(const char *sysattr, char **ret) {
return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
(void) sd_device_get_sysattr_value(device, sysattr, &s);
- if (!isempty(s)) {
- b = strdup(s);
- if (!b)
- return -ENOMEM;
- }
- if (ret)
- *ret = TAKE_PTR(b);
-
- return !isempty(s);
+ return strdup_to_full(ret, empty_to_null(s));
}
static int get_hardware_serial(char **ret) {
- int r;
+ _cleanup_free_ char *b = NULL;
+ int r = 0;
+
+ FOREACH_STRING(attr, "product_serial", "board_serial") {
+ r = get_hardware_firmware_data(attr, &b);
+ if (r != 0 && !ERRNO_IS_NEG_DEVICE_ABSENT(r))
+ break;
+ }
+ if (r < 0)
+ return r;
+ if (r == 0)
+ return -ENOENT;
- r = get_hardware_firmware_data("product_serial", ret);
- if (r <= 0)
- return get_hardware_firmware_data("board_serial", ret);
+ /* Do some superficial validation: do not allow CCs and make sure D-Bus won't kick us off the bus
+ * because we send invalid UTF-8 data */
- return r;
+ if (string_has_cc(b, /* ok= */ NULL))
+ return -ENOENT;
+
+ if (!utf8_is_valid(b))
+ return -ENOENT;
+
+ if (ret)
+ *ret = TAKE_PTR(b);
+
+ return 0;
}
static int get_firmware_version(char **ret) {
- return get_hardware_firmware_data("bios_version", ret);
+ return get_hardware_firmware_data("bios_version", ret);
}
static int get_firmware_vendor(char **ret) {
- return get_hardware_firmware_data("bios_vendor", ret);
+ return get_hardware_firmware_data("bios_vendor", ret);
}
static int get_firmware_date(usec_t *ret) {
- _cleanup_free_ char *bios_date = NULL, *month = NULL, *day = NULL, *year = NULL;
- int r;
+ _cleanup_free_ char *bios_date = NULL, *month = NULL, *day = NULL, *year = NULL;
+ int r;
- assert(ret);
+ assert(ret);
- r = get_hardware_firmware_data("bios_date", &bios_date);
- if (r < 0)
+ r = get_hardware_firmware_data("bios_date", &bios_date);
+ if (r < 0)
return r;
- if (r == 0) {
+ if (r == 0) {
*ret = USEC_INFINITY;
return 0;
- }
+ }
- const char *p = bios_date;
- r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year, NULL);
- if (r < 0)
+ const char *p = bios_date;
+ r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year);
+ if (r < 0)
return r;
- if (r != 3) /* less than three args read? */
+ if (r != 3) /* less than three args read? */
return -EINVAL;
- if (!isempty(p)) /* more left in the string? */
+ if (!isempty(p)) /* more left in the string? */
return -EINVAL;
- unsigned m, d, y;
- r = safe_atou_full(month, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &m);
- if (r < 0)
+ unsigned m, d, y;
+ r = safe_atou_full(month, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &m);
+ if (r < 0)
return r;
- if (m < 1 || m > 12)
+ if (m < 1 || m > 12)
return -EINVAL;
- m -= 1;
+ m -= 1;
- r = safe_atou_full(day, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &d);
- if (r < 0)
+ r = safe_atou_full(day, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &d);
+ if (r < 0)
return r;
- if (d < 1 || d > 31)
+ if (d < 1 || d > 31)
return -EINVAL;
- r = safe_atou_full(year, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &y);
- if (r < 0)
+ r = safe_atou_full(year, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &y);
+ if (r < 0)
return r;
- if (y < 1970 || y > (unsigned) INT_MAX)
+ if (y < 1970 || y > (unsigned) INT_MAX)
return -EINVAL;
- y -= 1900;
+ y -= 1900;
- struct tm tm = {
+ struct tm tm = {
.tm_mday = d,
.tm_mon = m,
.tm_year = y,
- };
- time_t v = timegm(&tm);
- if (v == (time_t) -1)
+ };
+ time_t v = timegm(&tm);
+ if (v == (time_t) -1)
return -errno;
- if (tm.tm_mday != (int) d || tm.tm_mon != (int) m || tm.tm_year != (int) y)
+ if (tm.tm_mday != (int) d || tm.tm_mon != (int) m || tm.tm_year != (int) y)
return -EINVAL; /* date was not normalized? (e.g. "30th of feb") */
- *ret = (usec_t) v * USEC_PER_SEC;
+ *ret = (usec_t) v * USEC_PER_SEC;
- return 0;
+ return 0;
}
static const char* valid_chassis(const char *chassis) {
@@ -1033,6 +1043,22 @@ static int property_get_boot_id(
return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
}
+static int property_get_vsock_cid(
+ sd_bus *bus,
+ const char *path,
+ const char *interface,
+ const char *property,
+ sd_bus_message *reply,
+ void *userdata,
+ sd_bus_error *error) {
+
+ unsigned local_cid = VMADDR_CID_ANY;
+
+ (void) vsock_get_local_cid(&local_cid);
+
+ return sd_bus_message_append(reply, "u", (uint32_t) local_cid);
+}
+
static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
Context *c = ASSERT_PTR(userdata);
const char *name;
@@ -1054,13 +1080,12 @@ static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *
context_read_etc_hostname(c);
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
m,
- CAP_SYS_ADMIN,
"org.freedesktop.hostname1.set-hostname",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
error);
if (r < 0)
@@ -1101,13 +1126,12 @@ static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_
if (name && !hostname_is_valid(name, 0))
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
m,
- CAP_SYS_ADMIN,
"org.freedesktop.hostname1.set-static-hostname",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
error);
if (r < 0)
@@ -1177,17 +1201,15 @@ static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_mess
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
}
- /* Since the pretty hostname should always be changed at the
- * same time as the static one, use the same policy action for
- * both... */
+ /* Since the pretty hostname should always be changed at the same time as the static one, use the
+ * same policy action for both... */
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
m,
- CAP_SYS_ADMIN,
prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
error);
if (r < 0)
@@ -1259,13 +1281,12 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
if (r < 0)
return r;
- r = bus_verify_polkit_async(
+ r = bus_verify_polkit_async_full(
m,
- CAP_SYS_ADMIN,
"org.freedesktop.hostname1.get-product-uuid",
- NULL,
- interactive,
- UID_INVALID,
+ /* details= */ NULL,
+ /* good_user= */ UID_INVALID,
+ interactive ? POLKIT_ALLOW_INTERACTIVE : 0,
&c->polkit_registry,
error);
if (r < 0)
@@ -1297,7 +1318,6 @@ static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_err
}
static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_error *error) {
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_free_ char *serial = NULL;
Context *c = ASSERT_PTR(userdata);
int r;
@@ -1306,11 +1326,8 @@ static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_
r = bus_verify_polkit_async(
m,
- CAP_SYS_ADMIN,
"org.freedesktop.hostname1.get-hardware-serial",
- NULL,
- false,
- UID_INVALID,
+ /* details= */ NULL,
&c->polkit_registry,
error);
if (r < 0)
@@ -1320,49 +1337,26 @@ static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_
r = get_hardware_serial(&serial);
if (r < 0)
- return r;
-
- r = sd_bus_message_new_method_return(m, &reply);
- if (r < 0)
- return r;
+ return sd_bus_error_set(error, BUS_ERROR_NO_HARDWARE_SERIAL,
+ "Failed to read hardware serial from firmware.");
- r = sd_bus_message_append(reply, "s", serial);
- if (r < 0)
- return r;
-
- return sd_bus_send(NULL, reply, NULL);
+ return sd_bus_reply_method_return(m, "s", serial);
}
-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;
+ _cleanup_strv_free_ char **os_release_pairs = NULL, **machine_info_pairs = 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;
- Context *c = ASSERT_PTR(userdata);
- bool privileged;
+ unsigned local_cid = VMADDR_CID_ANY;
struct utsname u;
int r;
- assert(m);
-
- r = bus_verify_polkit_async(
- m,
- CAP_SYS_ADMIN,
- "org.freedesktop.hostname1.get-description",
- NULL,
- false,
- UID_INVALID,
- &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);
@@ -1415,6 +1409,11 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro
if (r < 0)
return log_error_errno(r, "Failed to get boot ID: %m");
+ (void) vsock_get_local_cid(&local_cid);
+
+ (void) load_os_release_pairs(/* root= */ NULL, &os_release_pairs);
+ (void) load_env_file_pairs(/* f=*/ NULL, "/etc/machine-info", &machine_info_pairs);
+
r = json_build(&v, JSON_BUILD_OBJECT(
JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn)),
JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])),
@@ -1432,6 +1431,8 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro
JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])),
JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])),
JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol),
+ JSON_BUILD_PAIR("OperatingSystemReleaseData", JSON_BUILD_STRV_ENV_PAIR(os_release_pairs)),
+ JSON_BUILD_PAIR("MachineInformationData", JSON_BUILD_STRV_ENV_PAIR(machine_info_pairs)),
JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor ?: c->data[PROP_HARDWARE_VENDOR])),
JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model ?: c->data[PROP_HARDWARE_MODEL])),
JSON_BUILD_PAIR("HardwareSerial", JSON_BUILD_STRING(serial)),
@@ -1441,24 +1442,47 @@ static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *erro
JSON_BUILD_PAIR_ID128("MachineID", machine_id),
JSON_BUILD_PAIR_ID128("BootID", boot_id),
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(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)),
+ JSON_BUILD_PAIR_CONDITION(local_cid == VMADDR_CID_ANY, "VSockCID", JSON_BUILD_NULL)));
if (r < 0)
return log_error_errno(r, "Failed to build JSON data: %m");
- r = json_variant_format(v, 0, &text);
- if (r < 0)
- return log_error_errno(r, "Failed to format JSON data: %m");
+ *ret = TAKE_PTR(v);
+ return 0;
+}
- r = sd_bus_message_new_method_return(m, &reply);
+static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
+ _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 = sd_bus_message_append(reply, "s", text);
+ r = json_variant_format(v, 0, &text);
if (r < 0)
- return r;
+ return log_error_errno(r, "Failed to format JSON data: %m");
- return sd_bus_send(NULL, reply, NULL);
+ return sd_bus_reply_method_return(m, "s", text);
}
static const sd_bus_vtable hostname_vtable[] = {
@@ -1486,6 +1510,7 @@ static const sd_bus_vtable hostname_vtable[] = {
SD_BUS_PROPERTY("FirmwareDate", "t", property_get_firmware_date, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MachineID", "ay", property_get_machine_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("VSockCID", "u", property_get_vsock_cid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD_WITH_ARGS("SetHostname",
SD_BUS_ARGS("s", hostname, "b", interactive),
@@ -1547,35 +1572,113 @@ static const BusObjectImplementation manager_object = {
.vtables = BUS_VTABLES(hostname_vtable),
};
-static int connect_bus(Context *c, sd_event *event, sd_bus **ret) {
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
+static int connect_bus(Context *c) {
int r;
assert(c);
- assert(event);
- assert(ret);
+ assert(c->event);
+ assert(!c->bus);
- r = sd_bus_default_system(&bus);
+ r = sd_bus_default_system(&c->bus);
if (r < 0)
return log_error_errno(r, "Failed to get system bus connection: %m");
- r = bus_add_implementation(bus, &manager_object, c);
+ r = bus_add_implementation(c->bus, &manager_object, c);
if (r < 0)
return r;
- r = bus_log_control_api_register(bus);
+ r = bus_log_control_api_register(c->bus);
if (r < 0)
return r;
- r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
+ r = sd_bus_request_name_async(c->bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to request name: %m");
- r = sd_bus_attach_event(bus, event, 0);
+ r = sd_bus_attach_event(c->bus, c->event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
- *ret = TAKE_PTR(bus);
+ 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,
+ &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;
}
@@ -1583,8 +1686,6 @@ static int run(int argc, char *argv[]) {
_cleanup_(context_destroy) Context context = {
.hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
};
- _cleanup_(sd_event_unrefp) sd_event *event = NULL;
- _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
log_setup();
@@ -1603,27 +1704,35 @@ static int run(int argc, char *argv[]) {
if (r < 0)
return r;
- assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
-
- r = sd_event_default(&event);
+ r = sd_event_default(&context.event);
if (r < 0)
return log_error_errno(r, "Failed to allocate event loop: %m");
- (void) sd_event_set_watchdog(event, true);
+ (void) sd_event_set_watchdog(context.event, true);
- r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
+ r = sd_event_set_signal_exit(context.event, true);
if (r < 0)
- return log_error_errno(r, "Failed to install SIGINT handler: %m");
+ return log_error_errno(r, "Failed to install SIGINT/SIGTERM handlers: %m");
- r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
+ r = connect_bus(&context);
if (r < 0)
- return log_error_errno(r, "Failed to install SIGTERM handler: %m");
+ return r;
- r = connect_bus(&context, event, &bus);
+ r = connect_varlink(&context);
if (r < 0)
return r;
- r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
+ r = sd_notify(false, NOTIFY_READY);
+ if (r < 0)
+ log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
+
+ r = bus_event_loop_with_idle(
+ context.event,
+ context.bus,
+ "org.freedesktop.hostname1",
+ DEFAULT_EXIT_USEC,
+ /* check_idle= */ NULL,
+ /* userdata= */ NULL);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");