]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/hostname/hostnamed.c
shared: split out polkit stuff from bus-util.c → bus-polkit.c
[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
f7340ab2 283 /* ... the transient host name, (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) {
da927ba9 457 log_error_errno(r, "Failed to set host name: %m");
1b4cd646 458 return sd_bus_error_set_errnof(error, r, "Failed to set hostname: %m");
66a4c743 459 }
7640a5de 460
66a4c743 461 log_info("Changed host name 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) {
da927ba9 509 log_error_errno(r, "Failed to set host name: %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) {
da927ba9 515 log_error_errno(r, "Failed to write static host name: %m");
1b4cd646 516 return sd_bus_error_set_errnof(error, r, "Failed to set static hostname: %m");
66a4c743 517 }
7640a5de 518
66a4c743 519 log_info("Changed static host name 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))
550 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid pretty host name '%s'", name);
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
LP
587 log_info("Changed %s to '%s'",
588 prop == PROP_PRETTY_HOSTNAME ? "pretty host name" :
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),
adacb957
LP
680 SD_BUS_METHOD("SetHostname", "sb", NULL, method_set_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
681 SD_BUS_METHOD("SetStaticHostname", "sb", NULL, method_set_static_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
682 SD_BUS_METHOD("SetPrettyHostname", "sb", NULL, method_set_pretty_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
683 SD_BUS_METHOD("SetIconName", "sb", NULL, method_set_icon_name, SD_BUS_VTABLE_UNPRIVILEGED),
684 SD_BUS_METHOD("SetChassis", "sb", NULL, method_set_chassis, SD_BUS_VTABLE_UNPRIVILEGED),
799298d6 685 SD_BUS_METHOD("SetDeployment", "sb", NULL, method_set_deployment, SD_BUS_VTABLE_UNPRIVILEGED),
ce0f1493 686 SD_BUS_METHOD("SetLocation", "sb", NULL, method_set_location, SD_BUS_VTABLE_UNPRIVILEGED),
21e627da 687 SD_BUS_METHOD("GetProductUUID", "b", "ay", method_get_product_uuid, SD_BUS_VTABLE_UNPRIVILEGED),
66a4c743
LP
688 SD_BUS_VTABLE_END,
689};
690
691static int connect_bus(Context *c, sd_event *event, sd_bus **_bus) {
4afd3348 692 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
7640a5de
LP
693 int r;
694
66a4c743
LP
695 assert(c);
696 assert(event);
d0baa06f
LP
697 assert(_bus);
698
76b54375 699 r = sd_bus_default_system(&bus);
23bbb0de
MS
700 if (r < 0)
701 return log_error_errno(r, "Failed to get system bus connection: %m");
d0baa06f 702
19befb2d 703 r = sd_bus_add_object_vtable(bus, NULL, "/org/freedesktop/hostname1", "org.freedesktop.hostname1", hostname_vtable, c);
23bbb0de
MS
704 if (r < 0)
705 return log_error_errno(r, "Failed to register object: %m");
d0baa06f 706
0c0b9306 707 r = sd_bus_request_name_async(bus, NULL, "org.freedesktop.hostname1", 0, NULL, NULL);
23bbb0de 708 if (r < 0)
0c0b9306 709 return log_error_errno(r, "Failed to request name: %m");
add10b5a 710
66a4c743 711 r = sd_bus_attach_event(bus, event, 0);
23bbb0de
MS
712 if (r < 0)
713 return log_error_errno(r, "Failed to attach bus to event loop: %m");
d0baa06f 714
1cc6c93a 715 *_bus = TAKE_PTR(bus);
d0baa06f 716
66a4c743 717 return 0;
d0baa06f
LP
718}
719
85ae63ee
YW
720static int run(int argc, char *argv[]) {
721 _cleanup_(context_clear) Context context = {};
4afd3348
LP
722 _cleanup_(sd_event_unrefp) sd_event *event = NULL;
723 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
d0baa06f 724 int r;
d0baa06f 725
6bf3c61c 726 log_setup_service();
7640a5de 727
4c12626c 728 umask(0022);
c3dacc8b 729 mac_selinux_init();
4c12626c 730
7640a5de
LP
731 if (argc != 1) {
732 log_error("This program takes no arguments.");
85ae63ee 733 return -EINVAL;
7640a5de
LP
734 }
735
b22c8bfc
YW
736 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
737
afc6adb5 738 r = sd_event_default(&event);
85ae63ee
YW
739 if (r < 0)
740 return log_error_errno(r, "Failed to allocate event loop: %m");
7640a5de 741
b22c8bfc
YW
742 (void) sd_event_set_watchdog(event, true);
743
744 r = sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
85ae63ee
YW
745 if (r < 0)
746 return log_error_errno(r, "Failed to install SIGINT handler: %m");
b22c8bfc
YW
747
748 r = sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
85ae63ee
YW
749 if (r < 0)
750 return log_error_errno(r, "Failed to install SIGTERM handler: %m");
cde93897 751
66a4c743 752 r = connect_bus(&context, event, &bus);
d0baa06f 753 if (r < 0)
85ae63ee 754 return r;
7640a5de 755
66a4c743 756 r = context_read_data(&context);
85ae63ee
YW
757 if (r < 0)
758 return log_error_errno(r, "Failed to read hostname and machine information: %m");
ad740100 759
37224a5f 760 r = bus_event_loop_with_idle(event, bus, "org.freedesktop.hostname1", DEFAULT_EXIT_USEC, NULL, NULL);
85ae63ee
YW
761 if (r < 0)
762 return log_error_errno(r, "Failed to run event loop: %m");
7640a5de 763
85ae63ee 764 return 0;
7640a5de 765}
85ae63ee
YW
766
767DEFINE_MAIN_FUNCTION(run);