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