]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
hostnamed: use sd_bus_reply_method_return() to shorten code a bit
[thirdparty/systemd.git] / src / hostname / hostnamed.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
7640a5de 2
7640a5de 3#include <errno.h>
f426cc5d 4#include <sys/utsname.h>
ca78ad1d
ZJS
5#include <sys/stat.h>
6#include <sys/types.h>
cf0fbc49 7#include <unistd.h>
7640a5de 8
19b8e712
LP
9#include "sd-device.h"
10
b5efdb8a 11#include "alloc-util.h"
21e627da 12#include "bus-common-errors.h"
ce6b138c 13#include "bus-get-properties.h"
ac9f55ed 14#include "bus-log-control-api.h"
269e4d2d 15#include "bus-polkit.h"
28db6fbf 16#include "constants.h"
9737e2c8 17#include "daemon-util.h"
686d13b9
LP
18#include "env-file-label.h"
19#include "env-file.h"
4d1a6904 20#include "env-util.h"
6bedfcbb 21#include "fileio-label.h"
ee228be1 22#include "fileio.h"
e2054217 23#include "hostname-setup.h"
958b66ea 24#include "hostname-util.h"
21e627da 25#include "id128-util.h"
7ecead8f 26#include "json.h"
85ae63ee 27#include "main-func.h"
36dd5ffd 28#include "missing_capability.h"
7782e0a0 29#include "nscd-flush.h"
d8b4d14d 30#include "nulstr-util.h"
d58ad743 31#include "os-util.h"
6bedfcbb 32#include "parse-util.h"
bb15fafe 33#include "path-util.h"
6bedfcbb 34#include "selinux-util.h"
fc021a5b 35#include "service-util.h"
b22c8bfc 36#include "signal-util.h"
19b8e712 37#include "socket-util.h"
d7f4ad20 38#include "stat-util.h"
60e4fb42 39#include "string-table.h"
6bedfcbb 40#include "strv.h"
ee104e11 41#include "user-util.h"
64724e05 42#include "utf8.h"
0a6598bb 43#include "varlink-io.systemd.Hostname.h"
6bedfcbb 44#include "virt.h"
91f9dcaf 45
799298d6
JG
46#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
47
f8da67cd
LP
48/* Properties we cache are indexed by an enum, to make invalidation easy and systematic (as we can iterate
49 * through them all, and they are uniformly strings). */
4fc7e4f3 50typedef enum {
d7f4ad20 51 /* Read from /etc/hostname */
7640a5de 52 PROP_STATIC_HOSTNAME,
d7f4ad20
LP
53
54 /* Read from /etc/machine-info */
7640a5de
LP
55 PROP_PRETTY_HOSTNAME,
56 PROP_ICON_NAME,
7871c8e9 57 PROP_CHASSIS,
799298d6 58 PROP_DEPLOYMENT,
ce0f1493 59 PROP_LOCATION,
0924ea2b
LP
60 PROP_HARDWARE_VENDOR,
61 PROP_HARDWARE_MODEL,
d7f4ad20
LP
62
63 /* Read from /etc/os-release (or /usr/lib/os-release) */
44c32988
DH
64 PROP_OS_PRETTY_NAME,
65 PROP_OS_CPE_NAME,
d7f4ad20 66 PROP_OS_HOME_URL,
b563d5ce 67 PROP_OS_SUPPORT_END,
d7f4ad20 68 _PROP_MAX,
2d93c20e 69 _PROP_INVALID = -EINVAL,
4fc7e4f3 70} HostProperty;
7640a5de 71
66a4c743
LP
72typedef struct Context {
73 char *data[_PROP_MAX];
d7f4ad20 74
60e4fb42
ZJS
75 HostnameSource hostname_source;
76
d7f4ad20
LP
77 struct stat etc_hostname_stat;
78 struct stat etc_os_release_stat;
79 struct stat etc_machine_info_stat;
80
96520e8b
LP
81 sd_event *event;
82 sd_bus *bus;
0a6598bb 83 VarlinkServer *varlink_server;
66a4c743
LP
84 Hashmap *polkit_registry;
85} Context;
ad740100 86
d7f4ad20 87static void context_reset(Context *c, uint64_t mask) {
66a4c743
LP
88 assert(c);
89
536970d4 90 for (int p = 0; p < _PROP_MAX; p++) {
d7f4ad20
LP
91 if (!FLAGS_SET(mask, UINT64_C(1) << p))
92 continue;
93
a1e58e8e 94 c->data[p] = mfree(c->data[p]);
d7f4ad20 95 }
7640a5de
LP
96}
97
cfb9433d 98static void context_destroy(Context *c) {
66a4c743
LP
99 assert(c);
100
d7f4ad20 101 context_reset(c, UINT64_MAX);
2a1ffd3e 102 hashmap_free(c->polkit_registry);
96520e8b
LP
103 sd_event_unref(c->event);
104 sd_bus_flush_close_unref(c->bus);
0a6598bb 105 varlink_server_unref(c->varlink_server);
66a4c743
LP
106}
107
d7f4ad20
LP
108static void context_read_etc_hostname(Context *c) {
109 struct stat current_stat = {};
7640a5de
LP
110 int r;
111
66a4c743
LP
112 assert(c);
113
d7f4ad20
LP
114 if (stat("/etc/hostname", &current_stat) >= 0 &&
115 stat_inode_unmodified(&c->etc_hostname_stat, &current_stat))
116 return;
117
118 context_reset(c, UINT64_C(1) << PROP_STATIC_HOSTNAME);
7640a5de 119
f35cb39e 120 r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
7640a5de 121 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
122 log_warning_errno(r, "Failed to read /etc/hostname, ignoring: %m");
123
124 c->etc_hostname_stat = current_stat;
125}
126
127static void context_read_machine_info(Context *c) {
128 struct stat current_stat = {};
129 int r;
130
131 assert(c);
132
133 if (stat("/etc/machine-info", &current_stat) >= 0 &&
134 stat_inode_unmodified(&c->etc_machine_info_stat, &current_stat))
135 return;
136
137 context_reset(c,
138 (UINT64_C(1) << PROP_PRETTY_HOSTNAME) |
139 (UINT64_C(1) << PROP_ICON_NAME) |
140 (UINT64_C(1) << PROP_CHASSIS) |
141 (UINT64_C(1) << PROP_DEPLOYMENT) |
38639aa2
LP
142 (UINT64_C(1) << PROP_LOCATION) |
143 (UINT64_C(1) << PROP_HARDWARE_VENDOR) |
144 (UINT64_C(1) << PROP_HARDWARE_MODEL));
7640a5de 145
aa8fbc74 146 r = parse_env_file(NULL, "/etc/machine-info",
66a4c743
LP
147 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
148 "ICON_NAME", &c->data[PROP_ICON_NAME],
149 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 150 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
4fc7e4f3 151 "LOCATION", &c->data[PROP_LOCATION],
0924ea2b
LP
152 "HARDWARE_VENDOR", &c->data[PROP_HARDWARE_VENDOR],
153 "HARDWARE_MODEL", &c->data[PROP_HARDWARE_MODEL]);
7640a5de 154 if (r < 0 && r != -ENOENT)
d7f4ad20
LP
155 log_warning_errno(r, "Failed to read /etc/machine-info, ignoring: %m");
156
157 c->etc_machine_info_stat = current_stat;
158}
159
160static void context_read_os_release(Context *c) {
02b7005e 161 _cleanup_free_ char *os_name = NULL, *os_pretty_name = NULL;
d7f4ad20
LP
162 struct stat current_stat = {};
163 int r;
164
165 assert(c);
166
167 if ((stat("/etc/os-release", &current_stat) >= 0 ||
168 stat("/usr/lib/os-release", &current_stat) >= 0) &&
169 stat_inode_unmodified(&c->etc_os_release_stat, &current_stat))
170 return;
171
172 context_reset(c,
173 (UINT64_C(1) << PROP_OS_PRETTY_NAME) |
174 (UINT64_C(1) << PROP_OS_CPE_NAME) |
b563d5ce
LP
175 (UINT64_C(1) << PROP_OS_HOME_URL) |
176 (UINT64_C(1) << PROP_OS_SUPPORT_END));
7640a5de 177
d58ad743 178 r = parse_os_release(NULL,
02b7005e 179 "PRETTY_NAME", &os_pretty_name,
b563d5ce
LP
180 "NAME", &os_name,
181 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
182 "HOME_URL", &c->data[PROP_OS_HOME_URL],
183 "SUPPORT_END", &c->data[PROP_OS_SUPPORT_END]);
44c32988 184 if (r < 0 && r != -ENOENT)
d7f4ad20 185 log_warning_errno(r, "Failed to read os-release file, ignoring: %m");
44c32988 186
02b7005e
LP
187 if (free_and_strdup(&c->data[PROP_OS_PRETTY_NAME], os_release_pretty_name(os_pretty_name, os_name)) < 0)
188 log_oom();
189
d7f4ad20 190 c->etc_os_release_stat = current_stat;
7640a5de
LP
191}
192
e7932afe
LP
193static bool use_dmi_data(void) {
194 int r;
195
196 r = getenv_bool("SYSTEMD_HOSTNAME_FORCE_DMI");
197 if (r >= 0) {
198 log_debug("Honouring $SYSTEMD_HOSTNAME_FORCE_DMI override: %s", yes_no(r));
199 return r;
200 }
201 if (r != -ENXIO)
202 log_debug_errno(r, "Failed to parse $SYSTEMD_HOSTNAME_FORCE_DMI, ignoring: %m");
203
204 if (detect_container() > 0) {
205 log_debug("Running in a container, not using DMI hardware data.");
206 return false;
207 }
208
209 return true;
210}
211
8c8b1800
YW
212static int get_dmi_data(const char *database_key, const char *regular_key, char **ret) {
213 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
214 _cleanup_free_ char *b = NULL;
215 const char *s = NULL;
216 int r;
217
e7932afe
LP
218 if (!use_dmi_data())
219 return -ENOENT;
220
8c8b1800
YW
221 r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
222 if (r < 0)
223 return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
224
225 if (database_key)
226 (void) sd_device_get_property_value(device, database_key, &s);
227 if (!s && regular_key)
228 (void) sd_device_get_property_value(device, regular_key, &s);
229
e6fccf02
LP
230 if (!ret)
231 return !!s;
232
8c8b1800
YW
233 if (s) {
234 b = strdup(s);
235 if (!b)
236 return -ENOMEM;
237 }
238
e6fccf02 239 *ret = TAKE_PTR(b);
8c8b1800
YW
240 return !!s;
241}
242
243static int get_hardware_vendor(char **ret) {
244 return get_dmi_data("ID_VENDOR_FROM_DATABASE", "ID_VENDOR", ret);
245}
246
247static int get_hardware_model(char **ret) {
248 return get_dmi_data("ID_MODEL_FROM_DATABASE", "ID_MODEL", ret);
249}
250
c52950c2 251static int get_hardware_firmware_data(const char *sysattr, char **ret) {
96976629 252 _cleanup_(sd_device_unrefp) sd_device *device = NULL;
96976629
YW
253 const char *s = NULL;
254 int r;
255
c52950c2
SS
256 assert(sysattr);
257
e7932afe
LP
258 if (!use_dmi_data())
259 return -ENOENT;
260
96976629
YW
261 r = sd_device_new_from_syspath(&device, "/sys/class/dmi/id");
262 if (r < 0)
263 return log_debug_errno(r, "Failed to open /sys/class/dmi/id device, ignoring: %m");
264
c52950c2 265 (void) sd_device_get_sysattr_value(device, sysattr, &s);
96976629 266
cb0734d5
LP
267 bool empty = isempty(s);
268
269 if (ret) {
270 if (empty)
271 *ret = NULL;
272 else {
273 _cleanup_free_ char *b = NULL;
274
275 b = strdup(s);
276 if (!b)
277 return -ENOMEM;
278
279 *ret = TAKE_PTR(b);
280 }
281 }
96976629 282
cb0734d5 283 return !empty;
96976629
YW
284}
285
c52950c2 286static int get_hardware_serial(char **ret) {
64724e05
LP
287 _cleanup_free_ char *b = NULL;
288 int r = 0;
289
290 FOREACH_STRING(attr, "product_serial", "board_serial") {
291 r = get_hardware_firmware_data(attr, &b);
292 if (r != 0 && !ERRNO_IS_NEG_DEVICE_ABSENT(r))
293 break;
294 }
295 if (r < 0)
296 return r;
297 if (r == 0)
298 return -ENOENT;
299
300 /* Do some superficial validation: do not allow CCs and make sure D-Bus won't kick us off the bus
301 * because we send invalid UTF-8 data */
302
303 if (string_has_cc(b, /* ok= */ NULL))
304 return -ENOENT;
305
306 if (!utf8_is_valid(b))
307 return -ENOENT;
c52950c2 308
64724e05
LP
309 if (ret)
310 *ret = TAKE_PTR(b);
c52950c2 311
64724e05 312 return 0;
c52950c2
SS
313}
314
315static int get_firmware_version(char **ret) {
f3525b78 316 return get_hardware_firmware_data("bios_version", ret);
c52950c2
SS
317}
318
f233bbd6 319static int get_firmware_vendor(char **ret) {
f3525b78 320 return get_hardware_firmware_data("bios_vendor", ret);
f233bbd6
JW
321}
322
ad8858c1 323static int get_firmware_date(usec_t *ret) {
f3525b78
LP
324 _cleanup_free_ char *bios_date = NULL, *month = NULL, *day = NULL, *year = NULL;
325 int r;
ad8858c1 326
f3525b78 327 assert(ret);
ad8858c1 328
f3525b78
LP
329 r = get_hardware_firmware_data("bios_date", &bios_date);
330 if (r < 0)
ad8858c1 331 return r;
f3525b78 332 if (r == 0) {
ad8858c1
JW
333 *ret = USEC_INFINITY;
334 return 0;
f3525b78 335 }
ad8858c1 336
f3525b78
LP
337 const char *p = bios_date;
338 r = extract_many_words(&p, "/", EXTRACT_DONT_COALESCE_SEPARATORS, &month, &day, &year, NULL);
339 if (r < 0)
ad8858c1 340 return r;
f3525b78 341 if (r != 3) /* less than three args read? */
ad8858c1 342 return -EINVAL;
f3525b78 343 if (!isempty(p)) /* more left in the string? */
ad8858c1
JW
344 return -EINVAL;
345
f3525b78
LP
346 unsigned m, d, y;
347 r = safe_atou_full(month, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &m);
348 if (r < 0)
ad8858c1 349 return r;
f3525b78 350 if (m < 1 || m > 12)
ad8858c1 351 return -EINVAL;
f3525b78 352 m -= 1;
ad8858c1 353
f3525b78
LP
354 r = safe_atou_full(day, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &d);
355 if (r < 0)
ad8858c1 356 return r;
f3525b78 357 if (d < 1 || d > 31)
ad8858c1
JW
358 return -EINVAL;
359
f3525b78
LP
360 r = safe_atou_full(year, 10 | SAFE_ATO_REFUSE_PLUS_MINUS | SAFE_ATO_REFUSE_LEADING_WHITESPACE, &y);
361 if (r < 0)
ad8858c1 362 return r;
f3525b78 363 if (y < 1970 || y > (unsigned) INT_MAX)
ad8858c1 364 return -EINVAL;
f3525b78 365 y -= 1900;
ad8858c1 366
f3525b78 367 struct tm tm = {
ad8858c1
JW
368 .tm_mday = d,
369 .tm_mon = m,
370 .tm_year = y,
f3525b78
LP
371 };
372 time_t v = timegm(&tm);
373 if (v == (time_t) -1)
ad8858c1 374 return -errno;
f3525b78 375 if (tm.tm_mday != (int) d || tm.tm_mon != (int) m || tm.tm_year != (int) y)
ad8858c1
JW
376 return -EINVAL; /* date was not normalized? (e.g. "30th of feb") */
377
f3525b78 378 *ret = (usec_t) v * USEC_PER_SEC;
ad8858c1 379
f3525b78 380 return 0;
ff4d26df
JW
381}
382
e6e6ca82 383static const char* valid_chassis(const char *chassis) {
7871c8e9
LP
384 assert(chassis);
385
e6e6ca82 386 return nulstr_get(
7871c8e9
LP
387 "vm\0"
388 "container\0"
389 "desktop\0"
390 "laptop\0"
34b52450 391 "convertible\0"
7871c8e9
LP
392 "server\0"
393 "tablet\0"
c49e59c1 394 "handset\0"
25fa306e
LP
395 "watch\0"
396 "embedded\0",
7871c8e9
LP
397 chassis);
398}
399
799298d6
JG
400static bool valid_deployment(const char *deployment) {
401 assert(deployment);
402
c2142cf1 403 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
404}
405
7871c8e9 406static const char* fallback_chassis(void) {
e6e6ca82 407 const char *chassis;
68cdeab3 408 _cleanup_free_ char *type = NULL;
1b86c7c5 409 Virtualization v;
7640a5de 410 unsigned t;
1b86c7c5 411 int r;
7871c8e9 412
75f86906 413 v = detect_virtualization();
2ac4d1d4
LP
414 if (v < 0)
415 log_debug_errno(v, "Failed to detect virtualization, ignoring: %m");
416 else if (VIRTUALIZATION_IS_VM(v))
7871c8e9 417 return "vm";
2ac4d1d4 418 else if (VIRTUALIZATION_IS_CONTAINER(v))
7871c8e9
LP
419 return "container";
420
219bfe38 421 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
2ac4d1d4 422 if (r < 0) {
105a4245 423 log_debug_errno(r, "Failed to read DMI chassis type, ignoring: %m");
219bfe38 424 goto try_acpi;
2ac4d1d4 425 }
7871c8e9
LP
426
427 r = safe_atou(type, &t);
2ac4d1d4 428 if (r < 0) {
68cdeab3 429 log_debug_errno(r, "Failed to parse DMI chassis type \"%s\", ignoring: %m", type);
219bfe38 430 goto try_acpi;
2ac4d1d4 431 }
7871c8e9 432
219bfe38 433 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
68cdeab3
ZJS
434 * additional guesswork on top of that.
435 *
67840dbf 436 * See the SMBIOS Specification 3.5.0 section 7.4.1 for details about the values listed here:
68cdeab3 437 *
67840dbf 438 * https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.5.0.pdf
7871c8e9
LP
439 */
440
219bfe38 441 switch (t) {
7871c8e9 442
67840dbf
LP
443 case 0x03: /* Desktop */
444 case 0x04: /* Low Profile Desktop */
445 case 0x06: /* Mini Tower */
446 case 0x07: /* Tower */
447 case 0x0D: /* All in one (i.e. PC built into monitor) */
448 case 0x23: /* Mini PC */
449 case 0x24: /* Stick PC */
7871c8e9
LP
450 return "desktop";
451
219bfe38
LP
452 case 0x8: /* Portable */
453 case 0x9: /* Laptop */
454 case 0xA: /* Notebook */
455 case 0xE: /* Sub Notebook */
7871c8e9 456 return "laptop";
7640a5de 457
219bfe38
LP
458 case 0xB: /* Hand Held */
459 return "handset";
460
461 case 0x11: /* Main Server Chassis */
462 case 0x1C: /* Blade */
463 case 0x1D: /* Blade Enclosure */
7871c8e9 464 return "server";
7640a5de 465
219bfe38 466 case 0x1E: /* Tablet */
7871c8e9 467 return "tablet";
b70af833
DH
468
469 case 0x1F: /* Convertible */
b4227dbb 470 case 0x20: /* Detachable */
b70af833 471 return "convertible";
2ac4d1d4 472
67840dbf
LP
473 case 0x21: /* IoT Gateway */
474 case 0x22: /* Embedded PC */
475 return "embedded";
476
2ac4d1d4
LP
477 default:
478 log_debug("Unhandled DMI chassis type 0x%02x, ignoring.", t);
7871c8e9
LP
479 }
480
219bfe38 481try_acpi:
68cdeab3 482 type = mfree(type);
219bfe38 483 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
2ac4d1d4 484 if (r < 0) {
105a4245 485 log_debug_errno(r, "Failed read ACPI PM profile, ignoring: %m");
e6e6ca82 486 goto try_devicetree;
2ac4d1d4 487 }
7640a5de
LP
488
489 r = safe_atou(type, &t);
2ac4d1d4 490 if (r < 0) {
68cdeab3 491 log_debug_errno(r, "Failed parse ACPI PM profile \"%s\", ignoring: %m", type);
e6e6ca82 492 goto try_devicetree;
2ac4d1d4 493 }
7640a5de 494
219bfe38
LP
495 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
496 *
497 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
498 *
499 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
41550d40 500 */
7640a5de 501
79893116 502 switch (t) {
7640a5de 503
219bfe38
LP
504 case 1: /* Desktop */
505 case 3: /* Workstation */
506 case 6: /* Appliance PC */
7871c8e9 507 return "desktop";
7640a5de 508
219bfe38 509 case 2: /* Mobile */
7871c8e9
LP
510 return "laptop";
511
219bfe38
LP
512 case 4: /* Enterprise Server */
513 case 5: /* SOHO Server */
514 case 7: /* Performance Server */
7871c8e9 515 return "server";
f3f4f008 516
219bfe38 517 case 8: /* Tablet */
f3f4f008 518 return "tablet";
2ac4d1d4
LP
519
520 default:
521 log_debug("Unhandled ACPI PM profile 0x%02x, ignoring.", t);
7640a5de
LP
522 }
523
e6e6ca82 524try_devicetree:
68cdeab3 525 type = mfree(type);
e6cbe697 526 r = read_one_line_file("/proc/device-tree/chassis-type", &type);
e6e6ca82
AF
527 if (r < 0) {
528 log_debug_errno(r, "Failed to read device-tree chassis type, ignoring: %m");
529 return NULL;
530 }
531
532 /* Note that the Devicetree specification uses the very same vocabulary
533 * of chassis types as we do, hence we do not need to translate these types:
534 *
535 * https://github.com/devicetree-org/devicetree-specification/blob/master/source/chapter3-devicenodes.rst */
536 chassis = valid_chassis(type);
537 if (!chassis)
68cdeab3 538 log_debug("Invalid device-tree chassis type \"%s\", ignoring.", type);
e6e6ca82 539 return chassis;
7640a5de
LP
540}
541
8c8b1800
YW
542static char* context_get_chassis(Context *c) {
543 const char *fallback;
544 char *dmi;
7871c8e9 545
66a4c743
LP
546 assert(c);
547
548 if (!isempty(c->data[PROP_CHASSIS]))
8c8b1800
YW
549 return strdup(c->data[PROP_CHASSIS]);
550
471fdebf 551 if (get_dmi_data("ID_CHASSIS", NULL, &dmi) > 0)
8c8b1800
YW
552 return dmi;
553
554 fallback = fallback_chassis();
555 if (fallback)
556 return strdup(fallback);
557
558 return NULL;
559}
560
561static char* context_fallback_icon_name(Context *c) {
562 _cleanup_free_ char *chassis = NULL;
563
564 assert(c);
7871c8e9 565
8c8b1800 566 chassis = context_get_chassis(c);
7871c8e9 567 if (chassis)
b910cc72 568 return strjoin("computer-", chassis);
7871c8e9
LP
569
570 return strdup("computer");
571}
572
aa994368
LP
573static int context_update_kernel_hostname(
574 Context *c,
575 const char *transient_hn) {
576
05c6f341 577 _cleanup_free_ char *_hn_free = NULL;
d39079fc 578 const char *hn;
60e4fb42 579 HostnameSource hns;
7d9ec609 580 int r;
7640a5de 581
66a4c743
LP
582 assert(c);
583
d39079fc 584 /* /etc/hostname has the highest preference ... */
60e4fb42 585 if (c->data[PROP_STATIC_HOSTNAME]) {
d39079fc 586 hn = c->data[PROP_STATIC_HOSTNAME];
60e4fb42 587 hns = HOSTNAME_STATIC;
c779a442 588
38b38500 589 /* ... the transient hostname, (ie: DHCP) comes next ... */
60e4fb42 590 } else if (transient_hn) {
aa994368 591 hn = transient_hn;
60e4fb42 592 hns = HOSTNAME_TRANSIENT;
7640a5de 593
c779a442 594 /* ... and the ultimate fallback */
60e4fb42 595 } else {
05c6f341
ZJS
596 hn = _hn_free = get_default_hostname();
597 if (!hn)
598 return log_oom();
599
8770c813 600 hns = HOSTNAME_DEFAULT;
60e4fb42 601 }
c779a442 602
7d9ec609
ZJS
603 r = sethostname_idempotent(hn);
604 if (r < 0)
60e4fb42
ZJS
605 return log_error_errno(r, "Failed to set hostname: %m");
606
607 if (c->hostname_source != hns) {
608 c->hostname_source = hns;
609 r = 1;
610 }
7640a5de 611
7782e0a0 612 (void) nscd_flush_cache(STRV_MAKE("hosts"));
60e4fb42
ZJS
613
614 if (r == 0)
615 log_debug("Hostname was already set to <%s>.", hn);
616 else {
617 log_info("Hostname set to <%s> (%s)", hn, hostname_source_to_string(hns));
618
619 hostname_update_source_hint(hn, hns);
620 }
621
efda832d 622 return r; /* 0 if no change, 1 if something was done */
7640a5de
LP
623}
624
ba12e41d
YW
625static void unset_statp(struct stat **p) {
626 if (!*p)
627 return;
628
629 **p = (struct stat) {};
630}
631
66a4c743 632static int context_write_data_static_hostname(Context *c) {
ba12e41d
YW
633 _cleanup_(unset_statp) struct stat *s = NULL;
634 int r;
635
66a4c743
LP
636 assert(c);
637
ba12e41d
YW
638 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
639 * already, even if we can't make it hit the disk. */
640 s = &c->etc_hostname_stat;
641
66a4c743 642 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
ba12e41d
YW
643 if (unlink("/etc/hostname") < 0 && errno != ENOENT)
644 return -errno;
645
646 TAKE_PTR(s);
7640a5de
LP
647 return 0;
648 }
536970d4 649
ba12e41d
YW
650 r = write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
651 if (r < 0)
652 return r;
653
654 TAKE_PTR(s);
655 return 0;
7640a5de
LP
656}
657
f200e8bb 658static int context_write_data_machine_info(Context *c) {
ba12e41d 659 _cleanup_(unset_statp) struct stat *s = NULL;
7640a5de
LP
660 static const char * const name[_PROP_MAX] = {
661 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 662 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
663 [PROP_CHASSIS] = "CHASSIS",
664 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 665 [PROP_LOCATION] = "LOCATION",
7640a5de 666 };
0ccad099 667 _cleanup_strv_free_ char **l = NULL;
536970d4 668 int r;
7640a5de 669
66a4c743
LP
670 assert(c);
671
ba12e41d
YW
672 /* Make sure that if we fail here, we invalidate the cached information, since it was updated
673 * already, even if we can't make it hit the disk. */
674 s = &c->etc_machine_info_stat;
675
aa8fbc74 676 r = load_env_file(NULL, "/etc/machine-info", &l);
7640a5de
LP
677 if (r < 0 && r != -ENOENT)
678 return r;
679
536970d4 680 for (int p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
7640a5de
LP
681 assert(name[p]);
682
f08231fe
ZJS
683 r = strv_env_assign(&l, name[p], empty_to_null(c->data[p]));
684 if (r < 0)
685 return r;
7640a5de
LP
686 }
687
688 if (strv_isempty(l)) {
ba12e41d
YW
689 if (unlink("/etc/machine-info") < 0 && errno != ENOENT)
690 return -errno;
7640a5de 691
ba12e41d 692 TAKE_PTR(s);
7640a5de
LP
693 return 0;
694 }
695
f155cb6d 696 r = write_env_file_label(AT_FDCWD, "/etc/machine-info", NULL, l);
ba12e41d
YW
697 if (r < 0)
698 return r;
699
700 TAKE_PTR(s);
701 return 0;
7640a5de
LP
702}
703
4fc7e4f3
YW
704static int property_get_hardware_property(
705 sd_bus_message *reply,
706 Context *c,
707 HostProperty prop,
708 int (*getter)(char **)) {
709
710 _cleanup_free_ char *from_dmi = NULL;
711
712 assert(reply);
713 assert(c);
0924ea2b 714 assert(IN_SET(prop, PROP_HARDWARE_VENDOR, PROP_HARDWARE_MODEL));
4fc7e4f3
YW
715 assert(getter);
716
717 context_read_machine_info(c);
718
719 if (isempty(c->data[prop]))
720 (void) getter(&from_dmi);
721
722 return sd_bus_message_append(reply, "s", from_dmi ?: c->data[prop]);
723}
724
b9d80698
FB
725static int property_get_hardware_vendor(
726 sd_bus *bus,
727 const char *path,
728 const char *interface,
729 const char *property,
730 sd_bus_message *reply,
731 void *userdata,
732 sd_bus_error *error) {
b9d80698 733
0924ea2b 734 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_VENDOR, get_hardware_vendor);
b9d80698
FB
735}
736
737static int property_get_hardware_model(
738 sd_bus *bus,
739 const char *path,
740 const char *interface,
741 const char *property,
742 sd_bus_message *reply,
743 void *userdata,
744 sd_bus_error *error) {
b9d80698 745
0924ea2b 746 return property_get_hardware_property(reply, userdata, PROP_HARDWARE_MODEL, get_hardware_model);
b9d80698
FB
747}
748
c52950c2
SS
749static int property_get_firmware_version(
750 sd_bus *bus,
751 const char *path,
752 const char *interface,
753 const char *property,
754 sd_bus_message *reply,
755 void *userdata,
756 sd_bus_error *error) {
757
758 _cleanup_free_ char *firmware_version = NULL;
759
760 (void) get_firmware_version(&firmware_version);
761
762 return sd_bus_message_append(reply, "s", firmware_version);
763}
764
f233bbd6
JW
765static int property_get_firmware_vendor(
766 sd_bus *bus,
767 const char *path,
768 const char *interface,
769 const char *property,
770 sd_bus_message *reply,
771 void *userdata,
772 sd_bus_error *error) {
773
774 _cleanup_free_ char *firmware_vendor = NULL;
775
776 (void) get_firmware_vendor(&firmware_vendor);
777
778 return sd_bus_message_append(reply, "s", firmware_vendor);
779}
780
ff4d26df
JW
781static int property_get_firmware_date(
782 sd_bus *bus,
783 const char *path,
784 const char *interface,
785 const char *property,
786 sd_bus_message *reply,
787 void *userdata,
788 sd_bus_error *error) {
789
ad8858c1 790 usec_t firmware_date = USEC_INFINITY;
ff4d26df
JW
791
792 (void) get_firmware_date(&firmware_date);
793
ad8858c1 794 return sd_bus_message_append(reply, "t", firmware_date);
ff4d26df 795}
aa994368
LP
796static int property_get_hostname(
797 sd_bus *bus,
798 const char *path,
799 const char *interface,
800 const char *property,
801 sd_bus_message *reply,
802 void *userdata,
803 sd_bus_error *error) {
804
05c6f341 805 _cleanup_free_ char *hn = NULL;
aa994368
LP
806 int r;
807
05c6f341
ZJS
808 r = gethostname_strict(&hn);
809 if (r < 0) {
810 if (r != -ENXIO)
811 return r;
aa994368 812
05c6f341
ZJS
813 hn = get_default_hostname();
814 if (!hn)
815 return -ENOMEM;
816 }
817
818 return sd_bus_message_append(reply, "s", hn);
aa994368
LP
819}
820
d7f4ad20
LP
821static int property_get_static_hostname(
822 sd_bus *bus,
823 const char *path,
824 const char *interface,
825 const char *property,
826 sd_bus_message *reply,
827 void *userdata,
828 sd_bus_error *error) {
829
99534007 830 Context *c = ASSERT_PTR(userdata);
d7f4ad20
LP
831
832 context_read_etc_hostname(c);
833
834 return sd_bus_message_append(reply, "s", c->data[PROP_STATIC_HOSTNAME]);
835}
836
8770c813 837static int property_get_default_hostname(
05c6f341
ZJS
838 sd_bus *bus,
839 const char *path,
840 const char *interface,
841 const char *property,
842 sd_bus_message *reply,
843 void *userdata,
844 sd_bus_error *error) {
845
61d44b6b
LP
846 _cleanup_free_ char *hn = NULL;
847
848 hn = get_default_hostname();
05c6f341
ZJS
849 if (!hn)
850 return log_oom();
851
852 return sd_bus_message_append(reply, "s", hn);
853}
ce6b138c 854
f2a434a5 855static void context_determine_hostname_source(Context *c) {
0995accd 856 _cleanup_free_ char *hostname = NULL;
f2a434a5
LP
857 int r;
858
859 assert(c);
860
861 if (c->hostname_source >= 0)
862 return;
863
0995accd 864 (void) gethostname_full(GET_HOSTNAME_ALLOW_LOCALHOST, &hostname);
f2a434a5
LP
865
866 if (streq_ptr(hostname, c->data[PROP_STATIC_HOSTNAME]))
867 c->hostname_source = HOSTNAME_STATIC;
868 else {
0995accd
YW
869 _cleanup_free_ char *fallback = NULL;
870
f2a434a5
LP
871 /* If the hostname was not set by us, try to figure out where it came from. If we set it to
872 * the default hostname, the file will tell us. We compare the string because it is possible
32e27670
LP
873 * that the hostname was set by an older version that had a different fallback, in the initrd
874 * or before we reexecuted. */
f2a434a5
LP
875
876 r = read_one_line_file("/run/systemd/default-hostname", &fallback);
877 if (r < 0 && r != -ENOENT)
878 log_warning_errno(r, "Failed to read /run/systemd/default-hostname, ignoring: %m");
879
880 if (streq_ptr(fallback, hostname))
881 c->hostname_source = HOSTNAME_DEFAULT;
882 else
883 c->hostname_source = HOSTNAME_TRANSIENT;
884 }
885}
886
60e4fb42
ZJS
887static int property_get_hostname_source(
888 sd_bus *bus,
889 const char *path,
890 const char *interface,
891 const char *property,
892 sd_bus_message *reply,
893 void *userdata,
894 sd_bus_error *error) {
895
99534007 896 Context *c = ASSERT_PTR(userdata);
60e4fb42
ZJS
897
898 context_read_etc_hostname(c);
f2a434a5 899 context_determine_hostname_source(c);
60e4fb42
ZJS
900
901 return sd_bus_message_append(reply, "s", hostname_source_to_string(c->hostname_source));
902}
903
d7f4ad20
LP
904static int property_get_machine_info_field(
905 sd_bus *bus,
906 const char *path,
907 const char *interface,
908 const char *property,
909 sd_bus_message *reply,
910 void *userdata,
911 sd_bus_error *error) {
912
913 sd_bus_slot *slot;
914 Context *c;
915
916 /* Acquire the context object without this property's userdata offset added. Explanation: we want
917 * access to two pointers here: a) the main context object we cache all properties in, and b) the
918 * pointer to the property field inside the context object that we are supposed to update and
919 * use. The latter (b) we get in the 'userdata' function parameter, and sd-bus calculates that for us
920 * from the 'userdata' pointer we supplied when the vtable was registered, with the offset we
921 * specified in the vtable added on top. To get the former (a) we need the 'userdata' pointer from
922 * the vtable registration directly, without the offset added. Hence we ask sd-bus what the slot
923 * object is (which encapsulates the vtable registration), and then query the 'userdata' field
924 * directly off it. */
925 assert_se(slot = sd_bus_get_current_slot(bus));
926 assert_se(c = sd_bus_slot_get_userdata(slot));
927
928 context_read_machine_info(c);
929
930 return sd_bus_message_append(reply, "s", *(char**) userdata);
931}
932
933static int property_get_os_release_field(
934 sd_bus *bus,
935 const char *path,
936 const char *interface,
937 const char *property,
938 sd_bus_message *reply,
939 void *userdata,
940 sd_bus_error *error) {
941
942 sd_bus_slot *slot;
943 Context *c;
944
945 /* As above, acquire the current context without this property's userdata offset added. */
946 assert_se(slot = sd_bus_get_current_slot(bus));
947 assert_se(c = sd_bus_slot_get_userdata(slot));
948
949 context_read_os_release(c);
950
951 return sd_bus_message_append(reply, "s", *(char**) userdata);
952}
953
b563d5ce
LP
954static int property_get_os_support_end(
955 sd_bus *bus,
956 const char *path,
957 const char *interface,
958 const char *property,
959 sd_bus_message *reply,
960 void *userdata,
961 sd_bus_error *error) {
962
963 Context *c = userdata;
964 usec_t eol = USEC_INFINITY;
965
966 context_read_os_release(c);
967
968 if (c->data[PROP_OS_SUPPORT_END])
969 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
970
971 return sd_bus_message_append(reply, "t", eol);
972}
973
66a4c743
LP
974static int property_get_icon_name(
975 sd_bus *bus,
976 const char *path,
977 const char *interface,
978 const char *property,
979 sd_bus_message *reply,
ebcf1f97
LP
980 void *userdata,
981 sd_bus_error *error) {
7640a5de 982
66a4c743
LP
983 _cleanup_free_ char *n = NULL;
984 Context *c = userdata;
985 const char *name;
7640a5de 986
d7f4ad20
LP
987 context_read_machine_info(c);
988
66a4c743
LP
989 if (isempty(c->data[PROP_ICON_NAME]))
990 name = n = context_fallback_icon_name(c);
7640a5de 991 else
66a4c743
LP
992 name = c->data[PROP_ICON_NAME];
993
994 if (!name)
995 return -ENOMEM;
7640a5de 996
ebcf1f97 997 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
998}
999
66a4c743
LP
1000static int property_get_chassis(
1001 sd_bus *bus,
1002 const char *path,
1003 const char *interface,
1004 const char *property,
1005 sd_bus_message *reply,
ebcf1f97
LP
1006 void *userdata,
1007 sd_bus_error *error) {
7871c8e9 1008
8c8b1800 1009 _cleanup_free_ char *chassis = NULL;
66a4c743 1010 Context *c = userdata;
7871c8e9 1011
d7f4ad20
LP
1012 context_read_machine_info(c);
1013
8c8b1800 1014 chassis = context_get_chassis(c);
7871c8e9 1015
8c8b1800 1016 return sd_bus_message_append(reply, "s", chassis);
7871c8e9
LP
1017}
1018
72f48cd3
LP
1019static int property_get_uname_field(
1020 sd_bus *bus,
1021 const char *path,
1022 const char *interface,
1023 const char *property,
1024 sd_bus_message *reply,
1025 void *userdata,
1026 sd_bus_error *error) {
1027
1028 struct utsname u;
1029
1030 assert_se(uname(&u) >= 0);
1031
1032 return sd_bus_message_append(reply, "s", (char*) &u + PTR_TO_SIZE(userdata));
1033}
1034
5db7eb21
YW
1035static int property_get_machine_id(
1036 sd_bus *bus,
1037 const char *path,
1038 const char *interface,
1039 const char *property,
1040 sd_bus_message *reply,
1041 void *userdata,
1042 sd_bus_error *error) {
1043
1044 sd_id128_t id;
1045 int r;
1046
1047 r = sd_id128_get_machine(&id);
1048 if (r < 0)
1049 return r;
1050
1051 return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
1052}
1053
1054static int property_get_boot_id(
1055 sd_bus *bus,
1056 const char *path,
1057 const char *interface,
1058 const char *property,
1059 sd_bus_message *reply,
1060 void *userdata,
1061 sd_bus_error *error) {
1062
1063 sd_id128_t id;
1064 int r;
1065
1066 r = sd_id128_get_boot(&id);
1067 if (r < 0)
1068 return r;
1069
1070 return bus_property_get_id128(bus, path, interface, property, reply, &id, error);
1071}
1072
19b8e712
LP
1073static int property_get_vsock_cid(
1074 sd_bus *bus,
1075 const char *path,
1076 const char *interface,
1077 const char *property,
1078 sd_bus_message *reply,
1079 void *userdata,
1080 sd_bus_error *error) {
1081
1082 unsigned local_cid = VMADDR_CID_ANY;
1083
1084 (void) vsock_get_local_cid(&local_cid);
1085
1086 return sd_bus_message_append(reply, "u", (uint32_t) local_cid);
1087}
1088
19070062 1089static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1090 Context *c = ASSERT_PTR(userdata);
66a4c743 1091 const char *name;
aa994368 1092 int interactive, r;
d200735e 1093
19070062 1094 assert(m);
19070062 1095
66a4c743
LP
1096 r = sd_bus_message_read(m, "sb", &name, &interactive);
1097 if (r < 0)
ebcf1f97 1098 return r;
d200735e 1099
60e4fb42 1100 name = empty_to_null(name);
7640a5de 1101
60e4fb42
ZJS
1102 /* We always go through with the procedure below without comparing to the current hostname, because
1103 * we might want to adjust hostname source information even if the actual hostname is unchanged. */
7640a5de 1104
f190ac48 1105 if (name && !hostname_is_valid(name, 0))
ebcf1f97 1106 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 1107
60e4fb42 1108 context_read_etc_hostname(c);
7640a5de 1109
7b36fb9f 1110 r = bus_verify_polkit_async_full(
c529695e 1111 m,
c529695e 1112 "org.freedesktop.hostname1.set-hostname",
7b36fb9f 1113 /* details= */ NULL,
c529695e 1114 interactive,
7b36fb9f 1115 /* good_user= */ UID_INVALID,
c529695e
LP
1116 &c->polkit_registry,
1117 error);
66a4c743 1118 if (r < 0)
ebcf1f97 1119 return r;
66a4c743
LP
1120 if (r == 0)
1121 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1122
aa994368 1123 r = context_update_kernel_hostname(c, name);
60e4fb42 1124 if (r < 0)
1b4cd646 1125 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
60e4fb42 1126 else if (r > 0)
efda832d
ZJS
1127 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
1128 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1129 "Hostname", "HostnameSource", NULL);
7640a5de 1130
df2d202e 1131 return sd_bus_reply_method_return(m, NULL);
66a4c743 1132}
7640a5de 1133
19070062 1134static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
99534007 1135 Context *c = ASSERT_PTR(userdata);
66a4c743 1136 const char *name;
102d8f81 1137 int interactive;
66a4c743 1138 int r;
7640a5de 1139
19070062 1140 assert(m);
19070062 1141
66a4c743
LP
1142 r = sd_bus_message_read(m, "sb", &name, &interactive);
1143 if (r < 0)
ebcf1f97 1144 return r;
7640a5de 1145
3c6f7c34 1146 name = empty_to_null(name);
7640a5de 1147
d7f4ad20
LP
1148 context_read_etc_hostname(c);
1149
66a4c743 1150 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 1151 return sd_bus_reply_method_return(m, NULL);
7640a5de 1152
60e4fb42 1153 if (name && !hostname_is_valid(name, 0))
c650f207
YW
1154 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
1155
7b36fb9f 1156 r = bus_verify_polkit_async_full(
c529695e 1157 m,
c529695e 1158 "org.freedesktop.hostname1.set-static-hostname",
7b36fb9f 1159 /* details= */ NULL,
c529695e 1160 interactive,
7b36fb9f 1161 /* good_user= */ UID_INVALID,
c529695e
LP
1162 &c->polkit_registry,
1163 error);
66a4c743 1164 if (r < 0)
ebcf1f97 1165 return r;
66a4c743
LP
1166 if (r == 0)
1167 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 1168
e8acf091 1169 r = free_and_strdup_warn(&c->data[PROP_STATIC_HOSTNAME], name);
c650f207
YW
1170 if (r < 0)
1171 return r;
7640a5de 1172
66a4c743
LP
1173 r = context_write_data_static_hostname(c);
1174 if (r < 0) {
38b38500 1175 log_error_errno(r, "Failed to write static hostname: %m");
957991b7
YW
1176 if (ERRNO_IS_PRIVILEGE(r))
1177 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/hostname.");
1178 if (r == -EROFS)
1179 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/hostname is in a read-only filesystem.");
1b4cd646 1180 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 1181 }
7640a5de 1182
60e4fb42
ZJS
1183 r = context_update_kernel_hostname(c, NULL);
1184 if (r < 0) {
1185 log_error_errno(r, "Failed to set hostname: %m");
1186 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
1187 }
7640a5de 1188
efda832d 1189 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m),
60e4fb42
ZJS
1190 "/org/freedesktop/hostname1", "org.freedesktop.hostname1",
1191 "StaticHostname", "Hostname", "HostnameSource", NULL);
7640a5de 1192
df2d202e 1193 return sd_bus_reply_method_return(m, NULL);
66a4c743 1194}
7640a5de 1195
19070062 1196static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 1197 int interactive;
66a4c743
LP
1198 const char *name;
1199 int r;
1200
1201 assert(c);
66a4c743
LP
1202 assert(m);
1203
1204 r = sd_bus_message_read(m, "sb", &name, &interactive);
1205 if (r < 0)
ebcf1f97 1206 return r;
66a4c743 1207
3c6f7c34 1208 name = empty_to_null(name);
66a4c743 1209
d7f4ad20
LP
1210 context_read_machine_info(c);
1211
66a4c743 1212 if (streq_ptr(name, c->data[prop]))
df2d202e 1213 return sd_bus_reply_method_return(m, NULL);
7640a5de 1214
c650f207
YW
1215 if (!isempty(name)) {
1216 /* The icon name might ultimately be used as file
1217 * name, so better be safe than sorry */
1218
1219 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
1220 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
1221 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 1222 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
1223 if (prop == PROP_CHASSIS && !valid_chassis(name))
1224 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
1225 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
1226 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
1227 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
1228 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
1229 }
1230
7b36fb9f
LP
1231 /* Since the pretty hostname should always be changed at the same time as the static one, use the
1232 * same policy action for both... */
66a4c743 1233
7b36fb9f 1234 r = bus_verify_polkit_async_full(
c529695e 1235 m,
c529695e 1236 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
7b36fb9f 1237 /* details= */ NULL,
c529695e 1238 interactive,
7b36fb9f 1239 /* good_user= */ UID_INVALID,
c529695e
LP
1240 &c->polkit_registry,
1241 error);
66a4c743 1242 if (r < 0)
ebcf1f97 1243 return r;
66a4c743
LP
1244 if (r == 0)
1245 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1246
e8acf091 1247 r = free_and_strdup_warn(&c->data[prop], name);
c650f207
YW
1248 if (r < 0)
1249 return r;
7640a5de 1250
f200e8bb 1251 r = context_write_data_machine_info(c);
66a4c743 1252 if (r < 0) {
da927ba9 1253 log_error_errno(r, "Failed to write machine info: %m");
957991b7
YW
1254 if (ERRNO_IS_PRIVILEGE(r))
1255 return sd_bus_error_set(error, BUS_ERROR_FILE_IS_PROTECTED, "Not allowed to update /etc/machine-info.");
1256 if (r == -EROFS)
1257 return sd_bus_error_set(error, BUS_ERROR_READ_ONLY_FILESYSTEM, "/etc/machine-info is in a read-only filesystem.");
1b4cd646 1258 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 1259 }
7640a5de 1260
66a4c743 1261 log_info("Changed %s to '%s'",
38b38500 1262 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 1263 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 1264 prop == PROP_LOCATION ? "location" :
66a4c743 1265 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 1266
19070062
LP
1267 (void) sd_bus_emit_properties_changed(
1268 sd_bus_message_get_bus(m),
1269 "/org/freedesktop/hostname1",
1270 "org.freedesktop.hostname1",
1271 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
1272 prop == PROP_DEPLOYMENT ? "Deployment" :
1273 prop == PROP_LOCATION ? "Location" :
1274 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 1275
df2d202e 1276 return sd_bus_reply_method_return(m, NULL);
66a4c743 1277}
7640a5de 1278
19070062
LP
1279static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1280 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
1281}
1282
19070062
LP
1283static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1284 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
1285}
1286
19070062
LP
1287static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1288 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
1289}
1290
19070062
LP
1291static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1292 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
1293}
1294
19070062
LP
1295static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1296 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
1297}
1298
21e627da
YW
1299static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
1300 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
99534007 1301 Context *c = ASSERT_PTR(userdata);
21e627da 1302 int interactive, r;
5704cd73 1303 sd_id128_t uuid;
21e627da
YW
1304
1305 assert(m);
21e627da 1306
21e627da
YW
1307 r = sd_bus_message_read(m, "b", &interactive);
1308 if (r < 0)
1309 return r;
1310
7b36fb9f 1311 r = bus_verify_polkit_async_full(
21e627da 1312 m,
21e627da 1313 "org.freedesktop.hostname1.get-product-uuid",
7b36fb9f 1314 /* details= */ NULL,
21e627da 1315 interactive,
7b36fb9f 1316 /* good_user= */ UID_INVALID,
21e627da
YW
1317 &c->polkit_registry,
1318 error);
1319 if (r < 0)
1320 return r;
1321 if (r == 0)
1322 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1323
66ee2298
LP
1324 r = id128_get_product(&uuid);
1325 if (r < 0) {
1326 if (r == -EADDRNOTAVAIL)
1327 log_debug_errno(r, "DMI product UUID is all 0x00 or all 0xFF, ignoring.");
1328 else
1329 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
1330 "Failed to read product UUID, ignoring: %m");
1331
1332 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID,
1333 "Failed to read product UUID from firmware.");
1334 }
1335
21e627da
YW
1336 r = sd_bus_message_new_method_return(m, &reply);
1337 if (r < 0)
1338 return r;
1339
c52e295d 1340 r = sd_bus_message_append_array(reply, 'y', uuid.bytes, sizeof(uuid.bytes));
21e627da
YW
1341 if (r < 0)
1342 return r;
1343
1344 return sd_bus_send(NULL, reply, NULL);
1345}
1346
96976629 1347static int method_get_hardware_serial(sd_bus_message *m, void *userdata, sd_bus_error *error) {
96976629 1348 _cleanup_free_ char *serial = NULL;
99534007 1349 Context *c = ASSERT_PTR(userdata);
ff28d259 1350 int r;
96976629
YW
1351
1352 assert(m);
96976629 1353
96976629
YW
1354 r = bus_verify_polkit_async(
1355 m,
96976629 1356 "org.freedesktop.hostname1.get-hardware-serial",
7b36fb9f 1357 /* details= */ NULL,
96976629
YW
1358 &c->polkit_registry,
1359 error);
1360 if (r < 0)
1361 return r;
1362 if (r == 0)
1363 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1364
1365 r = get_hardware_serial(&serial);
1366 if (r < 0)
171ddae1
LP
1367 return sd_bus_error_set(error, BUS_ERROR_NO_HARDWARE_SERIAL,
1368 "Failed to read hardware serial from firmware.");
96976629 1369
26d1c5b9 1370 return sd_bus_reply_method_return(m, "s", serial);
96976629
YW
1371}
1372
0a6598bb
LP
1373static int build_describe_response(Context *c, bool privileged, JsonVariant **ret) {
1374 _cleanup_free_ char *hn = NULL, *dhn = NULL, *in = NULL,
f233bbd6 1375 *chassis = NULL, *vendor = NULL, *model = NULL, *serial = NULL, *firmware_version = NULL,
ad8858c1 1376 *firmware_vendor = NULL;
db21c2ec 1377 _cleanup_strv_free_ char **os_release_pairs = NULL, **machine_info_pairs = NULL;
b563d5ce 1378 usec_t firmware_date = USEC_INFINITY, eol = USEC_INFINITY;
7ecead8f 1379 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
5db7eb21 1380 sd_id128_t machine_id, boot_id, product_uuid = SD_ID128_NULL;
19b8e712 1381 unsigned local_cid = VMADDR_CID_ANY;
7ecead8f
LP
1382 struct utsname u;
1383 int r;
1384
0a6598bb
LP
1385 assert(c);
1386 assert(ret);
7ecead8f
LP
1387
1388 context_read_etc_hostname(c);
1389 context_read_machine_info(c);
1390 context_read_os_release(c);
1391 context_determine_hostname_source(c);
1392
1393 r = gethostname_strict(&hn);
1394 if (r < 0) {
1395 if (r != -ENXIO)
1396 return log_error_errno(r, "Failed to read local host name: %m");
1397
1398 hn = get_default_hostname();
1399 if (!hn)
1400 return log_oom();
1401 }
1402
1403 dhn = get_default_hostname();
1404 if (!dhn)
1405 return log_oom();
1406
1407 if (isempty(c->data[PROP_ICON_NAME]))
1408 in = context_fallback_icon_name(c);
1409
8c8b1800 1410 chassis = context_get_chassis(c);
7ecead8f
LP
1411
1412 assert_se(uname(&u) >= 0);
1413
0924ea2b 1414 if (isempty(c->data[PROP_HARDWARE_VENDOR]))
4fc7e4f3 1415 (void) get_hardware_vendor(&vendor);
0924ea2b 1416 if (isempty(c->data[PROP_HARDWARE_MODEL]))
4fc7e4f3 1417 (void) get_hardware_model(&model);
7ecead8f 1418
96976629
YW
1419 if (privileged) {
1420 /* The product UUID and hardware serial is only available to privileged clients */
1421 (void) id128_get_product(&product_uuid);
1422 (void) get_hardware_serial(&serial);
1423 }
c52950c2 1424 (void) get_firmware_version(&firmware_version);
f233bbd6 1425 (void) get_firmware_vendor(&firmware_vendor);
ff4d26df 1426 (void) get_firmware_date(&firmware_date);
7ecead8f 1427
b563d5ce
LP
1428 if (c->data[PROP_OS_SUPPORT_END])
1429 (void) os_release_support_ended(c->data[PROP_OS_SUPPORT_END], /* quiet= */ false, &eol);
1430
5db7eb21
YW
1431 r = sd_id128_get_machine(&machine_id);
1432 if (r < 0)
1433 return log_error_errno(r, "Failed to get machine ID: %m");
1434
1435 r = sd_id128_get_boot(&boot_id);
1436 if (r < 0)
1437 return log_error_errno(r, "Failed to get boot ID: %m");
1438
19b8e712
LP
1439 (void) vsock_get_local_cid(&local_cid);
1440
db21c2ec
LP
1441 (void) load_os_release_pairs(/* root= */ NULL, &os_release_pairs);
1442 (void) load_env_file_pairs(/* f=*/ NULL, "/etc/machine-info", &machine_info_pairs);
1443
7ecead8f
LP
1444 r = json_build(&v, JSON_BUILD_OBJECT(
1445 JSON_BUILD_PAIR("Hostname", JSON_BUILD_STRING(hn)),
1446 JSON_BUILD_PAIR("StaticHostname", JSON_BUILD_STRING(c->data[PROP_STATIC_HOSTNAME])),
1447 JSON_BUILD_PAIR("PrettyHostname", JSON_BUILD_STRING(c->data[PROP_PRETTY_HOSTNAME])),
1448 JSON_BUILD_PAIR("DefaultHostname", JSON_BUILD_STRING(dhn)),
1449 JSON_BUILD_PAIR("HostnameSource", JSON_BUILD_STRING(hostname_source_to_string(c->hostname_source))),
1450 JSON_BUILD_PAIR("IconName", JSON_BUILD_STRING(in ?: c->data[PROP_ICON_NAME])),
8c8b1800 1451 JSON_BUILD_PAIR("Chassis", JSON_BUILD_STRING(chassis)),
7ecead8f
LP
1452 JSON_BUILD_PAIR("Deployment", JSON_BUILD_STRING(c->data[PROP_DEPLOYMENT])),
1453 JSON_BUILD_PAIR("Location", JSON_BUILD_STRING(c->data[PROP_LOCATION])),
1454 JSON_BUILD_PAIR("KernelName", JSON_BUILD_STRING(u.sysname)),
1455 JSON_BUILD_PAIR("KernelRelease", JSON_BUILD_STRING(u.release)),
1456 JSON_BUILD_PAIR("KernelVersion", JSON_BUILD_STRING(u.version)),
1457 JSON_BUILD_PAIR("OperatingSystemPrettyName", JSON_BUILD_STRING(c->data[PROP_OS_PRETTY_NAME])),
1458 JSON_BUILD_PAIR("OperatingSystemCPEName", JSON_BUILD_STRING(c->data[PROP_OS_CPE_NAME])),
1459 JSON_BUILD_PAIR("OperatingSystemHomeURL", JSON_BUILD_STRING(c->data[PROP_OS_HOME_URL])),
b563d5ce 1460 JSON_BUILD_PAIR_FINITE_USEC("OperatingSystemSupportEnd", eol),
db21c2ec
LP
1461 JSON_BUILD_PAIR("OperatingSystemReleaseData", JSON_BUILD_STRV_ENV_PAIR(os_release_pairs)),
1462 JSON_BUILD_PAIR("MachineInformationData", JSON_BUILD_STRV_ENV_PAIR(machine_info_pairs)),
0924ea2b
LP
1463 JSON_BUILD_PAIR("HardwareVendor", JSON_BUILD_STRING(vendor ?: c->data[PROP_HARDWARE_VENDOR])),
1464 JSON_BUILD_PAIR("HardwareModel", JSON_BUILD_STRING(model ?: c->data[PROP_HARDWARE_MODEL])),
96976629 1465 JSON_BUILD_PAIR("HardwareSerial", JSON_BUILD_STRING(serial)),
c52950c2 1466 JSON_BUILD_PAIR("FirmwareVersion", JSON_BUILD_STRING(firmware_version)),
f233bbd6 1467 JSON_BUILD_PAIR("FirmwareVendor", JSON_BUILD_STRING(firmware_vendor)),
ad8858c1 1468 JSON_BUILD_PAIR_FINITE_USEC("FirmwareDate", firmware_date),
5db7eb21
YW
1469 JSON_BUILD_PAIR_ID128("MachineID", machine_id),
1470 JSON_BUILD_PAIR_ID128("BootID", boot_id),
7ecead8f 1471 JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_ID128(product_uuid)),
19b8e712 1472 JSON_BUILD_PAIR_CONDITION(sd_id128_is_null(product_uuid), "ProductUUID", JSON_BUILD_NULL),
77986df6
LP
1473 JSON_BUILD_PAIR_CONDITION(local_cid != VMADDR_CID_ANY, "VSockCID", JSON_BUILD_UNSIGNED(local_cid)),
1474 JSON_BUILD_PAIR_CONDITION(local_cid == VMADDR_CID_ANY, "VSockCID", JSON_BUILD_NULL)));
7ecead8f
LP
1475 if (r < 0)
1476 return log_error_errno(r, "Failed to build JSON data: %m");
1477
0a6598bb
LP
1478 *ret = TAKE_PTR(v);
1479 return 0;
1480}
1481
1482static int method_describe(sd_bus_message *m, void *userdata, sd_bus_error *error) {
0a6598bb
LP
1483 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1484 Context *c = ASSERT_PTR(userdata);
1485 _cleanup_free_ char *text = NULL;
1486 bool privileged;
1487 int r;
1488
1489 assert(m);
1490
1491 r = bus_verify_polkit_async(
1492 m,
1493 "org.freedesktop.hostname1.get-description",
1494 /* details= */ NULL,
1495 &c->polkit_registry,
1496 error);
1497 if (r == 0)
1498 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1499
1500 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1501 * the product ID which we'll check explicitly. */
1502 privileged = r > 0;
1503
1504 r = build_describe_response(c, privileged, &v);
1505 if (r < 0)
1506 return r;
1507
7ecead8f
LP
1508 r = json_variant_format(v, 0, &text);
1509 if (r < 0)
1510 return log_error_errno(r, "Failed to format JSON data: %m");
1511
26d1c5b9 1512 return sd_bus_reply_method_return(m, "s", text);
7ecead8f
LP
1513}
1514
66a4c743
LP
1515static const sd_bus_vtable hostname_vtable[] = {
1516 SD_BUS_VTABLE_START(0),
aa994368 1517 SD_BUS_PROPERTY("Hostname", "s", property_get_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1518 SD_BUS_PROPERTY("StaticHostname", "s", property_get_static_hostname, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1519 SD_BUS_PROPERTY("PrettyHostname", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
8770c813 1520 SD_BUS_PROPERTY("DefaultHostname", "s", property_get_default_hostname, 0, SD_BUS_VTABLE_PROPERTY_CONST),
60e4fb42 1521 SD_BUS_PROPERTY("HostnameSource", "s", property_get_hostname_source, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
1522 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1523 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
d7f4ad20
LP
1524 SD_BUS_PROPERTY("Deployment", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
1525 SD_BUS_PROPERTY("Location", "s", property_get_machine_info_field, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
72f48cd3
LP
1526 SD_BUS_PROPERTY("KernelName", "s", property_get_uname_field, offsetof(struct utsname, sysname), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1527 SD_BUS_PROPERTY("KernelRelease", "s", property_get_uname_field, offsetof(struct utsname, release), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
1528 SD_BUS_PROPERTY("KernelVersion", "s", property_get_uname_field, offsetof(struct utsname, version), SD_BUS_VTABLE_ABSOLUTE_OFFSET|SD_BUS_VTABLE_PROPERTY_CONST),
d7f4ad20
LP
1529 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
1530 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
b563d5ce 1531 SD_BUS_PROPERTY("OperatingSystemSupportEnd", "t", property_get_os_support_end, 0, SD_BUS_VTABLE_PROPERTY_CONST),
d7f4ad20 1532 SD_BUS_PROPERTY("HomeURL", "s", property_get_os_release_field, offsetof(Context, data) + sizeof(char*) * PROP_OS_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
b9d80698
FB
1533 SD_BUS_PROPERTY("HardwareVendor", "s", property_get_hardware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1534 SD_BUS_PROPERTY("HardwareModel", "s", property_get_hardware_model, 0, SD_BUS_VTABLE_PROPERTY_CONST),
c52950c2 1535 SD_BUS_PROPERTY("FirmwareVersion", "s", property_get_firmware_version, 0, SD_BUS_VTABLE_PROPERTY_CONST),
f233bbd6 1536 SD_BUS_PROPERTY("FirmwareVendor", "s", property_get_firmware_vendor, 0, SD_BUS_VTABLE_PROPERTY_CONST),
ad8858c1 1537 SD_BUS_PROPERTY("FirmwareDate", "t", property_get_firmware_date, 0, SD_BUS_VTABLE_PROPERTY_CONST),
5db7eb21
YW
1538 SD_BUS_PROPERTY("MachineID", "ay", property_get_machine_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
1539 SD_BUS_PROPERTY("BootID", "ay", property_get_boot_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
19b8e712 1540 SD_BUS_PROPERTY("VSockCID", "u", property_get_vsock_cid, 0, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be 1541
92c9f47d
SS
1542 SD_BUS_METHOD_WITH_ARGS("SetHostname",
1543 SD_BUS_ARGS("s", hostname, "b", interactive),
1544 SD_BUS_NO_RESULT,
1545 method_set_hostname,
1546 SD_BUS_VTABLE_UNPRIVILEGED),
1547 SD_BUS_METHOD_WITH_ARGS("SetStaticHostname",
1548 SD_BUS_ARGS("s", hostname, "b", interactive),
1549 SD_BUS_NO_RESULT,
1550 method_set_static_hostname,
1551 SD_BUS_VTABLE_UNPRIVILEGED),
1552 SD_BUS_METHOD_WITH_ARGS("SetPrettyHostname",
1553 SD_BUS_ARGS("s", hostname, "b", interactive),
1554 SD_BUS_NO_RESULT,
1555 method_set_pretty_hostname,
1556 SD_BUS_VTABLE_UNPRIVILEGED),
1557 SD_BUS_METHOD_WITH_ARGS("SetIconName",
1558 SD_BUS_ARGS("s", icon, "b", interactive),
1559 SD_BUS_NO_RESULT,
1560 method_set_icon_name,
1561 SD_BUS_VTABLE_UNPRIVILEGED),
1562 SD_BUS_METHOD_WITH_ARGS("SetChassis",
1563 SD_BUS_ARGS("s", chassis, "b", interactive),
1564 SD_BUS_NO_RESULT,
1565 method_set_chassis,
1566 SD_BUS_VTABLE_UNPRIVILEGED),
1567 SD_BUS_METHOD_WITH_ARGS("SetDeployment",
1568 SD_BUS_ARGS("s", deployment, "b", interactive),
1569 SD_BUS_NO_RESULT,
1570 method_set_deployment,
1571 SD_BUS_VTABLE_UNPRIVILEGED),
1572 SD_BUS_METHOD_WITH_ARGS("SetLocation",
1573 SD_BUS_ARGS("s", location, "b", interactive),
1574 SD_BUS_NO_RESULT,
1575 method_set_location,
1576 SD_BUS_VTABLE_UNPRIVILEGED),
1577 SD_BUS_METHOD_WITH_ARGS("GetProductUUID",
1578 SD_BUS_ARGS("b", interactive),
1579 SD_BUS_RESULT("ay", uuid),
1580 method_get_product_uuid,
1581 SD_BUS_VTABLE_UNPRIVILEGED),
1582 SD_BUS_METHOD_WITH_ARGS("GetHardwareSerial",
1583 SD_BUS_NO_ARGS,
1584 SD_BUS_RESULT("s", serial),
1585 method_get_hardware_serial,
1586 SD_BUS_VTABLE_UNPRIVILEGED),
7ecead8f
LP
1587 SD_BUS_METHOD_WITH_ARGS("Describe",
1588 SD_BUS_NO_ARGS,
1589 SD_BUS_RESULT("s", json),
1590 method_describe,
1591 SD_BUS_VTABLE_UNPRIVILEGED),
106d79be 1592
66a4c743
LP
1593 SD_BUS_VTABLE_END,
1594};
1595
670139db
ZJS
1596static const BusObjectImplementation manager_object = {
1597 "/org/freedesktop/hostname1",
1598 "org.freedesktop.hostname1",
1599 .vtables = BUS_VTABLES(hostname_vtable),
1600};
1601
96520e8b 1602static int connect_bus(Context *c) {
7640a5de
LP
1603 int r;
1604
66a4c743 1605 assert(c);
96520e8b
LP
1606 assert(c->event);
1607 assert(!c->bus);
d0baa06f 1608
96520e8b 1609 r = sd_bus_default_system(&c->bus);
23bbb0de
MS
1610 if (r < 0)
1611 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 1612
96520e8b 1613 r = bus_add_implementation(c->bus, &manager_object, c);
23bbb0de 1614 if (r < 0)
670139db 1615 return r;
d0baa06f 1616
96520e8b 1617 r = bus_log_control_api_register(c->bus);
ac9f55ed
LP
1618 if (r < 0)
1619 return r;
1620
96520e8b 1621 r = sd_bus_request_name_async(c->bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 1622 if (r < 0)
0c0b9306 1623 return log_error_errno(r, "Failed to request name: %m");
add10b5a 1624
96520e8b 1625 r = sd_bus_attach_event(c->bus, c->event, 0);
23bbb0de
MS
1626 if (r < 0)
1627 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 1628
66a4c743 1629 return 0;
d0baa06f
LP
1630}
1631
0a6598bb
LP
1632static int vl_method_describe(Varlink *link, JsonVariant *parameters, VarlinkMethodFlags flags, void *userdata) {
1633 static const JsonDispatch dispatch_table[] = {
1634 VARLINK_DISPATCH_POLKIT_FIELD,
1635 {}
1636 };
1637
1638 Context *c = ASSERT_PTR(userdata);
1639 bool privileged;
1640 int r;
1641
1642 assert(link);
1643 assert(parameters);
1644
1645 r = varlink_dispatch(link, parameters, dispatch_table, /* userdata= */ NULL);
1646 if (r != 0)
1647 return r;
1648
1649 r = varlink_verify_polkit_async(
1650 link,
1651 c->bus,
1652 "org.freedesktop.hostname1.get-hardware-serial",
1653 /* details= */ NULL,
1654 /* good_user= */ UID_INVALID,
1655 &c->polkit_registry);
1656 if (r == 0)
1657 return 0; /* No authorization for now, but the async polkit stuff will call us again when it has it */
1658
1659 /* We ignore all authentication errors here, since most data is unprivileged, the one exception being
1660 * the product ID which we'll check explicitly. */
1661 privileged = r > 0;
1662
1663 if (json_variant_elements(parameters) > 0)
1664 return varlink_error_invalid_parameter(link, parameters);
1665
1666 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
1667 r = build_describe_response(c, privileged, &v);
1668 if (r < 0)
1669 return r;
1670
1671 return varlink_reply(link, v);
1672}
1673
1674static int connect_varlink(Context *c) {
1675 int r;
1676
1677 assert(c);
1678 assert(c->event);
1679 assert(!c->varlink_server);
1680
1681 r = varlink_server_new(&c->varlink_server, VARLINK_SERVER_ACCOUNT_UID|VARLINK_SERVER_INHERIT_USERDATA);
1682 if (r < 0)
1683 return log_error_errno(r, "Failed to allocate Varlink server: %m");
1684
1685 varlink_server_set_userdata(c->varlink_server, c);
1686
1687 r = varlink_server_add_interface(c->varlink_server, &vl_interface_io_systemd_Hostname);
1688 if (r < 0)
1689 return log_error_errno(r, "Failed to add Hostname interface to varlink server: %m");
1690
1691 r = varlink_server_bind_method_many(
1692 c->varlink_server,
1693 "io.systemd.Hostname.Describe", vl_method_describe);
1694 if (r < 0)
1695 return log_error_errno(r, "Failed to bind Varlink method calls: %m");
1696
1697 r = varlink_server_attach_event(c->varlink_server, c->event, SD_EVENT_PRIORITY_NORMAL);
1698 if (r < 0)
1699 return log_error_errno(r, "Failed to attach Varlink server to event loop: %m");
1700
1701 r = varlink_server_listen_auto(c->varlink_server);
1702 if (r < 0)
1703 return log_error_errno(r, "Failed to bind to passed Varlink sockets: %m");
1704 if (r == 0) {
1705 r = varlink_server_listen_address(c->varlink_server, "/run/systemd/io.systemd.Hostname", 0666);
1706 if (r < 0)
1707 return log_error_errno(r, "Failed to bind to Varlink socket: %m");
1708 }
1709
1710 return 0;
1711}
1712
85ae63ee 1713static int run(int argc, char *argv[]) {
60e4fb42
ZJS
1714 _cleanup_(context_destroy) Context context = {
1715 .hostname_source = _HOSTNAME_INVALID, /* appropriate value will be set later */
1716 };
d0baa06f 1717 int r;
d0baa06f 1718
d2acb93d 1719 log_setup();
7640a5de 1720
fc021a5b
ZJS
1721 r = service_parse_argv("systemd-hostnamed.service",
1722 "Manage the system hostname and related metadata.",
670139db
ZJS
1723 BUS_IMPLEMENTATIONS(&manager_object,
1724 &log_control_object),
fc021a5b
ZJS
1725 argc, argv);
1726 if (r <= 0)
1727 return r;
1728
4c12626c 1729 umask(0022);
a9ba0e32 1730
a452c807 1731 r = mac_init();
a9ba0e32
CG
1732 if (r < 0)
1733 return r;
4c12626c 1734
96520e8b 1735 r = sd_event_default(&context.event);
85ae63ee
YW
1736 if (r < 0)
1737 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 1738
96520e8b 1739 (void) sd_event_set_watchdog(context.event, true);
b22c8bfc 1740
96520e8b 1741 r = sd_event_set_signal_exit(context.event, true);
85ae63ee 1742 if (r < 0)
aefaeebe 1743 return log_error_errno(r, "Failed to install SIGINT/SIGTERM handlers: %m");
cde93897 1744
96520e8b 1745 r = connect_bus(&context);
d0baa06f 1746 if (r < 0)
85ae63ee 1747 return r;
7640a5de 1748
0a6598bb
LP
1749 r = connect_varlink(&context);
1750 if (r < 0)
1751 return r;
1752
9737e2c8
MY
1753 r = sd_notify(false, NOTIFY_READY);
1754 if (r < 0)
1755 log_warning_errno(r, "Failed to send readiness notification, ignoring: %m");
1756
96520e8b
LP
1757 r = bus_event_loop_with_idle(
1758 context.event,
1759 context.bus,
1760 "org.freedesktop.hostname1",
1761 DEFAULT_EXIT_USEC,
1762 /* check_idle= */ NULL,
1763 /* userdata= */ NULL);
85ae63ee
YW
1764 if (r < 0)
1765 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 1766
85ae63ee 1767 return 0;
7640a5de 1768}
85ae63ee
YW
1769
1770DEFINE_MAIN_FUNCTION(run);