]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
tree-wide: use "hostname" spelling everywhere
[thirdparty/systemd.git] / src / hostname / hostnamed.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
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
b5efdb8a 9#include "alloc-util.h"
21e627da 10#include "bus-common-errors.h"
269e4d2d 11#include "bus-polkit.h"
ad740100 12#include "def.h"
686d13b9
LP
13#include "env-file-label.h"
14#include "env-file.h"
4d1a6904 15#include "env-util.h"
6bedfcbb 16#include "fileio-label.h"
ee228be1 17#include "fileio.h"
958b66ea 18#include "hostname-util.h"
21e627da 19#include "id128-util.h"
85ae63ee 20#include "main-func.h"
36dd5ffd 21#include "missing_capability.h"
7782e0a0 22#include "nscd-flush.h"
d8b4d14d 23#include "nulstr-util.h"
d58ad743 24#include "os-util.h"
6bedfcbb 25#include "parse-util.h"
bb15fafe 26#include "path-util.h"
6bedfcbb 27#include "selinux-util.h"
b22c8bfc 28#include "signal-util.h"
6bedfcbb 29#include "strv.h"
ee104e11 30#include "user-util.h"
6bedfcbb
LP
31#include "util.h"
32#include "virt.h"
91f9dcaf 33
799298d6
JG
34#define VALID_DEPLOYMENT_CHARS (DIGITS LETTERS "-.:")
35
7640a5de
LP
36enum {
37 PROP_HOSTNAME,
38 PROP_STATIC_HOSTNAME,
39 PROP_PRETTY_HOSTNAME,
40 PROP_ICON_NAME,
7871c8e9 41 PROP_CHASSIS,
799298d6 42 PROP_DEPLOYMENT,
ce0f1493 43 PROP_LOCATION,
f426cc5d
DH
44 PROP_KERNEL_NAME,
45 PROP_KERNEL_RELEASE,
9be3455f 46 PROP_KERNEL_VERSION,
44c32988
DH
47 PROP_OS_PRETTY_NAME,
48 PROP_OS_CPE_NAME,
64928aa5 49 PROP_HOME_URL,
7640a5de
LP
50 _PROP_MAX
51};
52
66a4c743
LP
53typedef struct Context {
54 char *data[_PROP_MAX];
55 Hashmap *polkit_registry;
21e627da
YW
56 sd_id128_t uuid;
57 bool has_uuid;
66a4c743 58} Context;
ad740100 59
66a4c743 60static void context_reset(Context *c) {
7640a5de
LP
61 int p;
62
66a4c743
LP
63 assert(c);
64
1f6b4113 65 for (p = 0; p < _PROP_MAX; p++)
a1e58e8e 66 c->data[p] = mfree(c->data[p]);
7640a5de
LP
67}
68
85ae63ee 69static void context_clear(Context *c) {
66a4c743
LP
70 assert(c);
71
72 context_reset(c);
36e34057 73 bus_verify_polkit_async_registry_free(c->polkit_registry);
66a4c743
LP
74}
75
76static int context_read_data(Context *c) {
7640a5de 77 int r;
f426cc5d 78 struct utsname u;
7640a5de 79
66a4c743
LP
80 assert(c);
81
82 context_reset(c);
7640a5de 83
f426cc5d
DH
84 assert_se(uname(&u) >= 0);
85 c->data[PROP_KERNEL_NAME] = strdup(u.sysname);
86 c->data[PROP_KERNEL_RELEASE] = strdup(u.release);
9be3455f
DH
87 c->data[PROP_KERNEL_VERSION] = strdup(u.version);
88 if (!c->data[PROP_KERNEL_NAME] || !c->data[PROP_KERNEL_RELEASE] ||
89 !c->data[PROP_KERNEL_VERSION])
f426cc5d
DH
90 return -ENOMEM;
91
66a4c743
LP
92 c->data[PROP_HOSTNAME] = gethostname_malloc();
93 if (!c->data[PROP_HOSTNAME])
7640a5de
LP
94 return -ENOMEM;
95
f35cb39e 96 r = read_etc_hostname(NULL, &c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
97 if (r < 0 && r != -ENOENT)
98 return r;
99
aa8fbc74 100 r = parse_env_file(NULL, "/etc/machine-info",
66a4c743
LP
101 "PRETTY_HOSTNAME", &c->data[PROP_PRETTY_HOSTNAME],
102 "ICON_NAME", &c->data[PROP_ICON_NAME],
103 "CHASSIS", &c->data[PROP_CHASSIS],
799298d6 104 "DEPLOYMENT", &c->data[PROP_DEPLOYMENT],
13df9c39 105 "LOCATION", &c->data[PROP_LOCATION]);
7640a5de
LP
106 if (r < 0 && r != -ENOENT)
107 return r;
108
d58ad743
LP
109 r = parse_os_release(NULL,
110 "PRETTY_NAME", &c->data[PROP_OS_PRETTY_NAME],
111 "CPE_NAME", &c->data[PROP_OS_CPE_NAME],
112 "HOME_URL", &c->data[PROP_HOME_URL],
113 NULL);
44c32988
DH
114 if (r < 0 && r != -ENOENT)
115 return r;
116
21e627da 117 r = id128_read("/sys/class/dmi/id/product_uuid", ID128_UUID, &c->uuid);
8fa0de65
DJL
118 if (r == -ENOENT)
119 r = id128_read("/sys/firmware/devicetree/base/vm,uuid", ID128_UUID, &c->uuid);
21e627da 120 if (r < 0)
6839aa56
LP
121 log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_WARNING, r,
122 "Failed to read product UUID, ignoring: %m");
123 else if (sd_id128_is_null(c->uuid) || sd_id128_is_allf(c->uuid))
124 log_debug("DMI product UUID " SD_ID128_FORMAT_STR " is all 0x00 or all 0xFF, ignoring.", SD_ID128_FORMAT_VAL(c->uuid));
125 else
126 c->has_uuid = true;
21e627da 127
7640a5de
LP
128 return 0;
129}
130
7871c8e9 131static bool valid_chassis(const char *chassis) {
7871c8e9
LP
132 assert(chassis);
133
134 return nulstr_contains(
135 "vm\0"
136 "container\0"
137 "desktop\0"
138 "laptop\0"
34b52450 139 "convertible\0"
7871c8e9
LP
140 "server\0"
141 "tablet\0"
c49e59c1 142 "handset\0"
25fa306e
LP
143 "watch\0"
144 "embedded\0",
7871c8e9
LP
145 chassis);
146}
147
799298d6
JG
148static bool valid_deployment(const char *deployment) {
149 assert(deployment);
150
c2142cf1 151 return in_charset(deployment, VALID_DEPLOYMENT_CHARS);
799298d6
JG
152}
153
7871c8e9 154static const char* fallback_chassis(void) {
7640a5de
LP
155 char *type;
156 unsigned t;
219bfe38 157 int v, r;
7871c8e9 158
75f86906 159 v = detect_virtualization();
75f86906 160 if (VIRTUALIZATION_IS_VM(v))
7871c8e9 161 return "vm";
75f86906 162 if (VIRTUALIZATION_IS_CONTAINER(v))
7871c8e9
LP
163 return "container";
164
219bfe38 165 r = read_one_line_file("/sys/class/dmi/id/chassis_type", &type);
7871c8e9 166 if (r < 0)
219bfe38 167 goto try_acpi;
7871c8e9
LP
168
169 r = safe_atou(type, &t);
170 free(type);
171 if (r < 0)
219bfe38 172 goto try_acpi;
7871c8e9 173
219bfe38
LP
174 /* We only list the really obvious cases here. The DMI data is unreliable enough, so let's not do any
175 additional guesswork on top of that.
176
177 See the SMBIOS Specification 3.0 section 7.4.1 for details about the values listed here:
178
179 https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf
7871c8e9
LP
180 */
181
219bfe38 182 switch (t) {
7871c8e9 183
219bfe38
LP
184 case 0x3: /* Desktop */
185 case 0x4: /* Low Profile Desktop */
186 case 0x6: /* Mini Tower */
187 case 0x7: /* Tower */
7871c8e9
LP
188 return "desktop";
189
219bfe38
LP
190 case 0x8: /* Portable */
191 case 0x9: /* Laptop */
192 case 0xA: /* Notebook */
193 case 0xE: /* Sub Notebook */
7871c8e9 194 return "laptop";
7640a5de 195
219bfe38
LP
196 case 0xB: /* Hand Held */
197 return "handset";
198
199 case 0x11: /* Main Server Chassis */
200 case 0x1C: /* Blade */
201 case 0x1D: /* Blade Enclosure */
7871c8e9 202 return "server";
7640a5de 203
219bfe38 204 case 0x1E: /* Tablet */
7871c8e9 205 return "tablet";
b70af833
DH
206
207 case 0x1F: /* Convertible */
b4227dbb 208 case 0x20: /* Detachable */
b70af833 209 return "convertible";
7871c8e9
LP
210 }
211
219bfe38
LP
212try_acpi:
213 r = read_one_line_file("/sys/firmware/acpi/pm_profile", &type);
7640a5de
LP
214 if (r < 0)
215 return NULL;
216
217 r = safe_atou(type, &t);
218 free(type);
7640a5de
LP
219 if (r < 0)
220 return NULL;
221
219bfe38
LP
222 /* We only list the really obvious cases here as the ACPI data is not really super reliable.
223 *
224 * See the ACPI 5.0 Spec Section 5.2.9.1 for details:
225 *
226 * http://www.acpi.info/DOWNLOADS/ACPIspec50.pdf
41550d40 227 */
7640a5de 228
219bfe38 229 switch(t) {
7640a5de 230
219bfe38
LP
231 case 1: /* Desktop */
232 case 3: /* Workstation */
233 case 6: /* Appliance PC */
7871c8e9 234 return "desktop";
7640a5de 235
219bfe38 236 case 2: /* Mobile */
7871c8e9
LP
237 return "laptop";
238
219bfe38
LP
239 case 4: /* Enterprise Server */
240 case 5: /* SOHO Server */
241 case 7: /* Performance Server */
7871c8e9 242 return "server";
f3f4f008 243
219bfe38 244 case 8: /* Tablet */
f3f4f008 245 return "tablet";
7640a5de
LP
246 }
247
7640a5de
LP
248 return NULL;
249}
250
66a4c743 251static char* context_fallback_icon_name(Context *c) {
7871c8e9
LP
252 const char *chassis;
253
66a4c743
LP
254 assert(c);
255
256 if (!isempty(c->data[PROP_CHASSIS]))
b910cc72 257 return strjoin("computer-", c->data[PROP_CHASSIS]);
7871c8e9
LP
258
259 chassis = fallback_chassis();
260 if (chassis)
b910cc72 261 return strjoin("computer-", chassis);
7871c8e9
LP
262
263 return strdup("computer");
264}
265
c779a442 266static bool hostname_is_useful(const char *hn) {
fecc80c1 267 return !isempty(hn) && !is_localhost(hn);
c779a442
SW
268}
269
270static int context_update_kernel_hostname(Context *c) {
271 const char *static_hn;
7640a5de
LP
272 const char *hn;
273
66a4c743
LP
274 assert(c);
275
c779a442
SW
276 static_hn = c->data[PROP_STATIC_HOSTNAME];
277
278 /* /etc/hostname with something other than "localhost"
279 * has the highest preference ... */
280 if (hostname_is_useful(static_hn))
281 hn = static_hn;
282
38b38500 283 /* ... the transient hostname, (ie: DHCP) comes next ... */
c779a442 284 else if (!isempty(c->data[PROP_HOSTNAME]))
66a4c743 285 hn = c->data[PROP_HOSTNAME];
7640a5de 286
c779a442
SW
287 /* ... fallback to static "localhost.*" ignored above ... */
288 else if (!isempty(static_hn))
289 hn = static_hn;
290
291 /* ... and the ultimate fallback */
292 else
8146c32b 293 hn = FALLBACK_HOSTNAME;
c779a442 294
605f81a8 295 if (sethostname_idempotent(hn) < 0)
7640a5de
LP
296 return -errno;
297
7782e0a0
LP
298 (void) nscd_flush_cache(STRV_MAKE("hosts"));
299
7640a5de
LP
300 return 0;
301}
302
66a4c743 303static int context_write_data_static_hostname(Context *c) {
7640a5de 304
66a4c743
LP
305 assert(c);
306
307 if (isempty(c->data[PROP_STATIC_HOSTNAME])) {
7640a5de
LP
308
309 if (unlink("/etc/hostname") < 0)
310 return errno == ENOENT ? 0 : -errno;
311
312 return 0;
313 }
66a4c743 314 return write_string_file_atomic_label("/etc/hostname", c->data[PROP_STATIC_HOSTNAME]);
7640a5de
LP
315}
316
f200e8bb 317static int context_write_data_machine_info(Context *c) {
4f34ed54 318
7640a5de
LP
319 static const char * const name[_PROP_MAX] = {
320 [PROP_PRETTY_HOSTNAME] = "PRETTY_HOSTNAME",
7871c8e9 321 [PROP_ICON_NAME] = "ICON_NAME",
799298d6
JG
322 [PROP_CHASSIS] = "CHASSIS",
323 [PROP_DEPLOYMENT] = "DEPLOYMENT",
ce0f1493 324 [PROP_LOCATION] = "LOCATION",
7640a5de
LP
325 };
326
0ccad099 327 _cleanup_strv_free_ char **l = NULL;
7640a5de
LP
328 int r, p;
329
66a4c743
LP
330 assert(c);
331
aa8fbc74 332 r = load_env_file(NULL, "/etc/machine-info", &l);
7640a5de
LP
333 if (r < 0 && r != -ENOENT)
334 return r;
335
ce0f1493 336 for (p = PROP_PRETTY_HOSTNAME; p <= PROP_LOCATION; p++) {
d77ab3f7
LP
337 _cleanup_free_ char *t = NULL;
338 char **u;
7640a5de
LP
339
340 assert(name[p]);
341
66a4c743 342 if (isempty(c->data[p])) {
f8440af5 343 strv_env_unset(l, name[p]);
7640a5de
LP
344 continue;
345 }
346
605405c6 347 t = strjoin(name[p], "=", c->data[p]);
d77ab3f7 348 if (!t)
7640a5de 349 return -ENOMEM;
7640a5de
LP
350
351 u = strv_env_set(l, t);
7640a5de
LP
352 if (!u)
353 return -ENOMEM;
0ccad099 354
130d3d22 355 strv_free_and_replace(l, u);
7640a5de
LP
356 }
357
358 if (strv_isempty(l)) {
7640a5de
LP
359 if (unlink("/etc/machine-info") < 0)
360 return errno == ENOENT ? 0 : -errno;
361
362 return 0;
363 }
364
0ccad099 365 return write_env_file_label("/etc/machine-info", l);
7640a5de
LP
366}
367
66a4c743
LP
368static int property_get_icon_name(
369 sd_bus *bus,
370 const char *path,
371 const char *interface,
372 const char *property,
373 sd_bus_message *reply,
ebcf1f97
LP
374 void *userdata,
375 sd_bus_error *error) {
7640a5de 376
66a4c743
LP
377 _cleanup_free_ char *n = NULL;
378 Context *c = userdata;
379 const char *name;
7640a5de 380
66a4c743
LP
381 if (isempty(c->data[PROP_ICON_NAME]))
382 name = n = context_fallback_icon_name(c);
7640a5de 383 else
66a4c743
LP
384 name = c->data[PROP_ICON_NAME];
385
386 if (!name)
387 return -ENOMEM;
7640a5de 388
ebcf1f97 389 return sd_bus_message_append(reply, "s", name);
7640a5de
LP
390}
391
66a4c743
LP
392static int property_get_chassis(
393 sd_bus *bus,
394 const char *path,
395 const char *interface,
396 const char *property,
397 sd_bus_message *reply,
ebcf1f97
LP
398 void *userdata,
399 sd_bus_error *error) {
7871c8e9 400
66a4c743
LP
401 Context *c = userdata;
402 const char *name;
7871c8e9 403
66a4c743 404 if (isempty(c->data[PROP_CHASSIS]))
7871c8e9
LP
405 name = fallback_chassis();
406 else
66a4c743 407 name = c->data[PROP_CHASSIS];
7871c8e9 408
ebcf1f97 409 return sd_bus_message_append(reply, "s", name);
7871c8e9
LP
410}
411
19070062 412static int method_set_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
413 Context *c = userdata;
414 const char *name;
102d8f81 415 int interactive;
66a4c743 416 int r;
d200735e 417
19070062
LP
418 assert(m);
419 assert(c);
420
66a4c743
LP
421 r = sd_bus_message_read(m, "sb", &name, &interactive);
422 if (r < 0)
ebcf1f97 423 return r;
d200735e 424
66a4c743
LP
425 if (isempty(name))
426 name = c->data[PROP_STATIC_HOSTNAME];
7640a5de 427
66a4c743 428 if (isempty(name))
8146c32b 429 name = FALLBACK_HOSTNAME;
7640a5de 430
8fb49443 431 if (!hostname_is_valid(name, false))
ebcf1f97 432 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid hostname '%s'", name);
7640a5de 433
66a4c743 434 if (streq_ptr(name, c->data[PROP_HOSTNAME]))
df2d202e 435 return sd_bus_reply_method_return(m, NULL);
7640a5de 436
c529695e
LP
437 r = bus_verify_polkit_async(
438 m,
439 CAP_SYS_ADMIN,
440 "org.freedesktop.hostname1.set-hostname",
403ed0e5 441 NULL,
c529695e
LP
442 interactive,
443 UID_INVALID,
444 &c->polkit_registry,
445 error);
66a4c743 446 if (r < 0)
ebcf1f97 447 return r;
66a4c743
LP
448 if (r == 0)
449 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 450
c650f207
YW
451 r = free_and_strdup(&c->data[PROP_HOSTNAME], name);
452 if (r < 0)
453 return r;
7640a5de 454
c779a442 455 r = context_update_kernel_hostname(c);
66a4c743 456 if (r < 0) {
38b38500 457 log_error_errno(r, "Failed to set hostname: %m");
1b4cd646 458 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
66a4c743 459 }
7640a5de 460
38b38500 461 log_info("Changed hostname to '%s'", strna(c->data[PROP_HOSTNAME]));
7640a5de 462
19070062 463 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "Hostname", NULL);
7640a5de 464
df2d202e 465 return sd_bus_reply_method_return(m, NULL);
66a4c743 466}
7640a5de 467
19070062 468static int method_set_static_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
66a4c743
LP
469 Context *c = userdata;
470 const char *name;
102d8f81 471 int interactive;
66a4c743 472 int r;
7640a5de 473
19070062
LP
474 assert(m);
475 assert(c);
476
66a4c743
LP
477 r = sd_bus_message_read(m, "sb", &name, &interactive);
478 if (r < 0)
ebcf1f97 479 return r;
7640a5de 480
3c6f7c34 481 name = empty_to_null(name);
7640a5de 482
66a4c743 483 if (streq_ptr(name, c->data[PROP_STATIC_HOSTNAME]))
df2d202e 484 return sd_bus_reply_method_return(m, NULL);
7640a5de 485
c650f207
YW
486 if (!isempty(name) && !hostname_is_valid(name, false))
487 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid static hostname '%s'", name);
488
c529695e
LP
489 r = bus_verify_polkit_async(
490 m,
491 CAP_SYS_ADMIN,
492 "org.freedesktop.hostname1.set-static-hostname",
403ed0e5 493 NULL,
c529695e
LP
494 interactive,
495 UID_INVALID,
496 &c->polkit_registry,
497 error);
66a4c743 498 if (r < 0)
ebcf1f97 499 return r;
66a4c743
LP
500 if (r == 0)
501 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
7640a5de 502
c650f207
YW
503 r = free_and_strdup(&c->data[PROP_STATIC_HOSTNAME], name);
504 if (r < 0)
505 return r;
7640a5de 506
c779a442
SW
507 r = context_update_kernel_hostname(c);
508 if (r < 0) {
38b38500 509 log_error_errno(r, "Failed to set hostname: %m");
1b4cd646 510 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
c779a442
SW
511 }
512
66a4c743
LP
513 r = context_write_data_static_hostname(c);
514 if (r < 0) {
38b38500 515 log_error_errno(r, "Failed to write static hostname: %m");
1b4cd646 516 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 517 }
7640a5de 518
38b38500 519 log_info("Changed static hostname to '%s'", strna(c->data[PROP_STATIC_HOSTNAME]));
7640a5de 520
19070062 521 (void) sd_bus_emit_properties_changed(sd_bus_message_get_bus(m), "/org/freedesktop/hostname1", "org.freedesktop.hostname1", "StaticHostname", NULL);
7640a5de 522
df2d202e 523 return sd_bus_reply_method_return(m, NULL);
66a4c743 524}
7640a5de 525
19070062 526static int set_machine_info(Context *c, sd_bus_message *m, int prop, sd_bus_message_handler_t cb, sd_bus_error *error) {
102d8f81 527 int interactive;
66a4c743
LP
528 const char *name;
529 int r;
530
531 assert(c);
66a4c743
LP
532 assert(m);
533
534 r = sd_bus_message_read(m, "sb", &name, &interactive);
535 if (r < 0)
ebcf1f97 536 return r;
66a4c743 537
3c6f7c34 538 name = empty_to_null(name);
66a4c743
LP
539
540 if (streq_ptr(name, c->data[prop]))
df2d202e 541 return sd_bus_reply_method_return(m, NULL);
7640a5de 542
c650f207
YW
543 if (!isempty(name)) {
544 /* The icon name might ultimately be used as file
545 * name, so better be safe than sorry */
546
547 if (prop == PROP_ICON_NAME && !filename_is_valid(name))
548 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid icon name '%s'", name);
549 if (prop == PROP_PRETTY_HOSTNAME && string_has_cc(name, NULL))
38b38500 550 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty hostname '%s'", name);
c650f207
YW
551 if (prop == PROP_CHASSIS && !valid_chassis(name))
552 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid chassis '%s'", name);
553 if (prop == PROP_DEPLOYMENT && !valid_deployment(name))
554 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid deployment '%s'", name);
555 if (prop == PROP_LOCATION && string_has_cc(name, NULL))
556 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid location '%s'", name);
557 }
558
66a4c743
LP
559 /* Since the pretty hostname should always be changed at the
560 * same time as the static one, use the same policy action for
561 * both... */
562
c529695e
LP
563 r = bus_verify_polkit_async(
564 m,
565 CAP_SYS_ADMIN,
566 prop == PROP_PRETTY_HOSTNAME ? "org.freedesktop.hostname1.set-static-hostname" : "org.freedesktop.hostname1.set-machine-info",
403ed0e5 567 NULL,
c529695e
LP
568 interactive,
569 UID_INVALID,
570 &c->polkit_registry,
571 error);
66a4c743 572 if (r < 0)
ebcf1f97 573 return r;
66a4c743
LP
574 if (r == 0)
575 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
576
c650f207
YW
577 r = free_and_strdup(&c->data[prop], name);
578 if (r < 0)
579 return r;
7640a5de 580
f200e8bb 581 r = context_write_data_machine_info(c);
66a4c743 582 if (r < 0) {
da927ba9 583 log_error_errno(r, "Failed to write machine info: %m");
1b4cd646 584 return sd_bus_error_set_errnof(error, r, "Failed to write machine info: %m");
66a4c743 585 }
7640a5de 586
66a4c743 587 log_info("Changed %s to '%s'",
38b38500 588 prop == PROP_PRETTY_HOSTNAME ? "pretty hostname" :
799298d6 589 prop == PROP_DEPLOYMENT ? "deployment" :
ce0f1493 590 prop == PROP_LOCATION ? "location" :
66a4c743 591 prop == PROP_CHASSIS ? "chassis" : "icon name", strna(c->data[prop]));
7640a5de 592
19070062
LP
593 (void) sd_bus_emit_properties_changed(
594 sd_bus_message_get_bus(m),
595 "/org/freedesktop/hostname1",
596 "org.freedesktop.hostname1",
597 prop == PROP_PRETTY_HOSTNAME ? "PrettyHostname" :
598 prop == PROP_DEPLOYMENT ? "Deployment" :
599 prop == PROP_LOCATION ? "Location" :
600 prop == PROP_CHASSIS ? "Chassis" : "IconName" , NULL);
7640a5de 601
df2d202e 602 return sd_bus_reply_method_return(m, NULL);
66a4c743 603}
7640a5de 604
19070062
LP
605static int method_set_pretty_hostname(sd_bus_message *m, void *userdata, sd_bus_error *error) {
606 return set_machine_info(userdata, m, PROP_PRETTY_HOSTNAME, method_set_pretty_hostname, error);
7640a5de
LP
607}
608
19070062
LP
609static int method_set_icon_name(sd_bus_message *m, void *userdata, sd_bus_error *error) {
610 return set_machine_info(userdata, m, PROP_ICON_NAME, method_set_icon_name, error);
66a4c743
LP
611}
612
19070062
LP
613static int method_set_chassis(sd_bus_message *m, void *userdata, sd_bus_error *error) {
614 return set_machine_info(userdata, m, PROP_CHASSIS, method_set_chassis, error);
66a4c743
LP
615}
616
19070062
LP
617static int method_set_deployment(sd_bus_message *m, void *userdata, sd_bus_error *error) {
618 return set_machine_info(userdata, m, PROP_DEPLOYMENT, method_set_deployment, error);
799298d6
JG
619}
620
19070062
LP
621static int method_set_location(sd_bus_message *m, void *userdata, sd_bus_error *error) {
622 return set_machine_info(userdata, m, PROP_LOCATION, method_set_location, error);
ce0f1493
LP
623}
624
21e627da
YW
625static int method_get_product_uuid(sd_bus_message *m, void *userdata, sd_bus_error *error) {
626 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
627 Context *c = userdata;
628 int interactive, r;
629
630 assert(m);
631 assert(c);
632
633 if (!c->has_uuid)
634 return sd_bus_error_set(error, BUS_ERROR_NO_PRODUCT_UUID, "Failed to read product UUID from /sys/class/dmi/id/product_uuid");
635
636 r = sd_bus_message_read(m, "b", &interactive);
637 if (r < 0)
638 return r;
639
640 r = bus_verify_polkit_async(
641 m,
642 CAP_SYS_ADMIN,
643 "org.freedesktop.hostname1.get-product-uuid",
644 NULL,
645 interactive,
646 UID_INVALID,
647 &c->polkit_registry,
648 error);
649 if (r < 0)
650 return r;
651 if (r == 0)
652 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
653
654 r = sd_bus_message_new_method_return(m, &reply);
655 if (r < 0)
656 return r;
657
658 r = sd_bus_message_append_array(reply, 'y', &c->uuid, sizeof(c->uuid));
659 if (r < 0)
660 return r;
661
662 return sd_bus_send(NULL, reply, NULL);
663}
664
66a4c743
LP
665static const sd_bus_vtable hostname_vtable[] = {
666 SD_BUS_VTABLE_START(0),
caffbef6 667 SD_BUS_PROPERTY("Hostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
66a4c743
LP
668 SD_BUS_PROPERTY("StaticHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_STATIC_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
669 SD_BUS_PROPERTY("PrettyHostname", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_PRETTY_HOSTNAME, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
670 SD_BUS_PROPERTY("IconName", "s", property_get_icon_name, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
671 SD_BUS_PROPERTY("Chassis", "s", property_get_chassis, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
ce0f1493
LP
672 SD_BUS_PROPERTY("Deployment", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_DEPLOYMENT, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
673 SD_BUS_PROPERTY("Location", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_LOCATION, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
f426cc5d
DH
674 SD_BUS_PROPERTY("KernelName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
675 SD_BUS_PROPERTY("KernelRelease", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_RELEASE, SD_BUS_VTABLE_PROPERTY_CONST),
9be3455f 676 SD_BUS_PROPERTY("KernelVersion", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_KERNEL_VERSION, SD_BUS_VTABLE_PROPERTY_CONST),
44c32988
DH
677 SD_BUS_PROPERTY("OperatingSystemPrettyName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_PRETTY_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
678 SD_BUS_PROPERTY("OperatingSystemCPEName", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_OS_CPE_NAME, SD_BUS_VTABLE_PROPERTY_CONST),
64928aa5 679 SD_BUS_PROPERTY("HomeURL", "s", NULL, offsetof(Context, data) + sizeof(char*) * PROP_HOME_URL, SD_BUS_VTABLE_PROPERTY_CONST),
106d79be
ZJS
680
681 SD_BUS_METHOD_WITH_NAMES("SetHostname",
682 "sb",
683 SD_BUS_PARAM(hostname)
684 SD_BUS_PARAM(interactive),
685 NULL,,
686 method_set_hostname,
687 SD_BUS_VTABLE_UNPRIVILEGED),
688 SD_BUS_METHOD_WITH_NAMES("SetStaticHostname",
689 "sb",
690 SD_BUS_PARAM(hostname)
691 SD_BUS_PARAM(interactive),
692 NULL,,
693 method_set_static_hostname,
694 SD_BUS_VTABLE_UNPRIVILEGED),
695 SD_BUS_METHOD_WITH_NAMES("SetPrettyHostname",
696 "sb",
697 SD_BUS_PARAM(hostname)
698 SD_BUS_PARAM(interactive),
699 NULL,,
700 method_set_pretty_hostname,
701 SD_BUS_VTABLE_UNPRIVILEGED),
702 SD_BUS_METHOD_WITH_NAMES("SetIconName",
703 "sb",
704 SD_BUS_PARAM(icon)
705 SD_BUS_PARAM(interactive),
706 NULL,,
707 method_set_icon_name,
708 SD_BUS_VTABLE_UNPRIVILEGED),
709 SD_BUS_METHOD_WITH_NAMES("SetChassis",
710 "sb",
711 SD_BUS_PARAM(chassis)
712 SD_BUS_PARAM(interactive),
713 NULL,,
714 method_set_chassis,
715 SD_BUS_VTABLE_UNPRIVILEGED),
716 SD_BUS_METHOD_WITH_NAMES("SetDeployment",
717 "sb",
718 SD_BUS_PARAM(deployment)
719 SD_BUS_PARAM(interactive),
720 NULL,,
721 method_set_deployment,
722 SD_BUS_VTABLE_UNPRIVILEGED),
723 SD_BUS_METHOD_WITH_NAMES("SetLocation",
724 "sb",
725 SD_BUS_PARAM(location)
726 SD_BUS_PARAM(interactive),
727 NULL,,
728 method_set_location,
729 SD_BUS_VTABLE_UNPRIVILEGED),
730 SD_BUS_METHOD_WITH_NAMES("GetProductUUID",
731 "b",
732 SD_BUS_PARAM(interactive),
733 "ay",
734 SD_BUS_PARAM(uuid),
735 method_get_product_uuid,
736 SD_BUS_VTABLE_UNPRIVILEGED),
737
66a4c743
LP
738 SD_BUS_VTABLE_END,
739};
740
741static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
4afd3348 742 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
7640a5de
LP
743 int r;
744
66a4c743
LP
745 assert(c);
746 assert(event);
d0baa06f
LP
747 assert(_bus);
748
76b54375 749 r = sd_bus_default_system(&bus);
23bbb0de
MS
750 if (r < 0)
751 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 752
19befb2d 753 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
23bbb0de
MS
754 if (r < 0)
755 return log_error_errno(r, "Failed to register object: %m");
d0baa06f 756
0c0b9306 757 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 758 if (r < 0)
0c0b9306 759 return log_error_errno(r, "Failed to request name: %m");
add10b5a 760
66a4c743 761 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
762 if (r < 0)
763 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 764
1cc6c93a 765 *_bus = TAKE_PTR(bus);
d0baa06f 766
66a4c743 767 return 0;
d0baa06f
LP
768}
769
85ae63ee
YW
770static int run(int argc, char *argv[]) {
771 _cleanup_(context_clear) Context context = {};
4afd3348
LP
772 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
773 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d0baa06f 774 int r;
d0baa06f 775
6bf3c61c 776 log_setup_service();
7640a5de 777
4c12626c 778 umask(0022);
c3dacc8b 779 mac_selinux_init();
4c12626c 780
7640a5de
LP
781 if (argc != 1) {
782 log_error("This program takes no arguments.");
85ae63ee 783 return -EINVAL;
7640a5de
LP
784 }
785
b22c8bfc
YW
786 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
787
afc6adb5 788 r = sd_event_default(&event);
85ae63ee
YW
789 if (r < 0)
790 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 791
b22c8bfc
YW
792 (void) sd_event_set_watchdog(event, true);
793
794 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
85ae63ee
YW
795 if (r < 0)
796 return log_error_errno(r, "Failed to install SIGINT handler: %m");
b22c8bfc
YW
797
798 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
85ae63ee
YW
799 if (r < 0)
800 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
cde93897 801
66a4c743 802 r = connect_bus(&context, event, &bus);
d0baa06f 803 if (r < 0)
85ae63ee 804 return r;
7640a5de 805
66a4c743 806 r = context_read_data(&context);
85ae63ee
YW
807 if (r < 0)
808 return log_error_errno(r, "Failed to read hostname and machine information: %m");
ad740100 809
37224a5f 810 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
85ae63ee
YW
811 if (r < 0)
812 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 813
85ae63ee 814 return 0;
7640a5de 815}
85ae63ee
YW
816
817DEFINE_MAIN_FUNCTION(run);