1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/vm_sockets.h>
6 #include "sd-varlink.h"
8 #include "bus-polkit.h"
9 #include "discover-image.h"
10 #include "errno-util.h"
11 #include "format-util.h"
13 #include "image-policy.h"
14 #include "image-varlink.h"
15 #include "json-util.h"
16 #include "local-addresses.h"
18 #include "machine-varlink.h"
20 #include "machined-varlink.h"
21 #include "string-util.h"
23 #include "user-util.h"
24 #include "varlink-io.systemd.Machine.h"
25 #include "varlink-io.systemd.MachineImage.h"
26 #include "varlink-io.systemd.UserDatabase.h"
27 #include "varlink-io.systemd.service.h"
28 #include "varlink-util.h"
30 typedef struct LookupParameters
{
31 const char *user_name
;
32 const char *group_name
;
40 static int build_user_json(const char *user_name
, uid_t uid
, const char *real_name
, sd_json_variant
**ret
) {
42 assert(uid_is_valid(uid
));
45 return sd_json_buildo(
47 SD_JSON_BUILD_PAIR("record", SD_JSON_BUILD_OBJECT(
48 SD_JSON_BUILD_PAIR("userName", SD_JSON_BUILD_STRING(user_name
)),
49 SD_JSON_BUILD_PAIR("uid", SD_JSON_BUILD_UNSIGNED(uid
)),
50 SD_JSON_BUILD_PAIR("gid", SD_JSON_BUILD_UNSIGNED(GID_NOBODY
)),
51 SD_JSON_BUILD_PAIR_CONDITION(!isempty(real_name
), "realName", SD_JSON_BUILD_STRING(real_name
)),
52 SD_JSON_BUILD_PAIR("homeDirectory", JSON_BUILD_CONST_STRING("/")),
53 SD_JSON_BUILD_PAIR("shell", JSON_BUILD_CONST_STRING(NOLOGIN
)),
54 SD_JSON_BUILD_PAIR("locked", SD_JSON_BUILD_BOOLEAN(true)),
55 SD_JSON_BUILD_PAIR("service", JSON_BUILD_CONST_STRING("io.systemd.Machine")),
56 SD_JSON_BUILD_PAIR("disposition", JSON_BUILD_CONST_STRING("container")))));
59 static bool user_match_lookup_parameters(LookupParameters
*p
, const char *name
, uid_t uid
) {
62 if (p
->user_name
&& !streq(name
, p
->user_name
))
65 if (uid_is_valid(p
->uid
) && uid
!= p
->uid
)
71 static int user_lookup_uid(Manager
*m
, uid_t uid
, char **ret_name
, char **ret_real_name
) {
72 _cleanup_free_
char *n
= NULL
, *rn
= NULL
;
78 assert(uid_is_valid(uid
));
80 assert(ret_real_name
);
82 if (uid
< 0x10000) /* Host UID range */
85 r
= manager_find_machine_for_uid(m
, uid
, &machine
, &converted_uid
);
91 if (asprintf(&n
, "vu-%s-" UID_FMT
, machine
->name
, converted_uid
) < 0)
94 /* Don't synthesize invalid user/group names (too long...) */
95 if (!valid_user_group_name(n
, 0))
98 if (asprintf(&rn
, "UID " UID_FMT
" of Container %s", converted_uid
, machine
->name
) < 0)
101 /* Don't synthesize invalid real names either, but since this field doesn't matter much, simply invalidate things */
102 if (!valid_gecos(rn
))
105 *ret_name
= TAKE_PTR(n
);
106 *ret_real_name
= TAKE_PTR(rn
);
110 static int user_lookup_name(Manager
*m
, const char *name
, uid_t
*ret_uid
, char **ret_real_name
) {
111 _cleanup_free_
char *mn
= NULL
, *rn
= NULL
;
112 uid_t uid
, converted_uid
;
119 assert(ret_real_name
);
121 if (!valid_user_group_name(name
, 0))
124 e
= startswith(name
, "vu-");
132 if (parse_uid(d
+ 1, &uid
) < 0)
135 mn
= strndup(e
, d
- e
);
139 machine
= hashmap_get(m
->machines
, mn
);
143 if (machine
->class != MACHINE_CONTAINER
)
146 r
= machine_translate_uid(machine
, uid
, &converted_uid
);
150 if (asprintf(&rn
, "UID " UID_FMT
" of Container %s", uid
, machine
->name
) < 0)
152 if (!valid_gecos(rn
))
155 *ret_uid
= converted_uid
;
156 *ret_real_name
= TAKE_PTR(rn
);
160 static int vl_method_get_user_record(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
162 static const sd_json_dispatch_field dispatch_table
[] = {
163 { "uid", SD_JSON_VARIANT_UNSIGNED
, sd_json_dispatch_uid_gid
, offsetof(LookupParameters
, uid
), 0 },
164 { "userName", SD_JSON_VARIANT_STRING
, json_dispatch_const_user_group_name
, offsetof(LookupParameters
, user_name
), SD_JSON_RELAX
},
165 { "service", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(LookupParameters
, service
), 0 },
169 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
;
170 LookupParameters p
= {
173 _cleanup_free_
char *found_name
= NULL
, *found_real_name
= NULL
;
174 uid_t found_uid
= UID_INVALID
, uid
;
175 Manager
*m
= ASSERT_PTR(userdata
);
181 r
= sd_varlink_dispatch(link
, parameters
, dispatch_table
, &p
);
185 if (!streq_ptr(p
.service
, "io.systemd.Machine"))
186 return sd_varlink_error(link
, "io.systemd.UserDatabase.BadService", NULL
);
188 if (uid_is_valid(p
.uid
))
189 r
= user_lookup_uid(m
, p
.uid
, &found_name
, &found_real_name
);
190 else if (p
.user_name
)
191 r
= user_lookup_name(m
, p
.user_name
, &found_uid
, &found_real_name
);
193 return sd_varlink_error(link
, "io.systemd.UserDatabase.EnumerationNotSupported", NULL
);
195 return sd_varlink_error(link
, "io.systemd.UserDatabase.NoRecordFound", NULL
);
199 uid
= uid_is_valid(found_uid
) ? found_uid
: p
.uid
;
200 un
= found_name
?: p
.user_name
;
202 if (!user_match_lookup_parameters(&p
, un
, uid
))
203 return sd_varlink_error(link
, "io.systemd.UserDatabase.ConflictingRecordFound", NULL
);
205 r
= build_user_json(un
, uid
, found_real_name
, &v
);
209 return sd_varlink_reply(link
, v
);
212 static int build_group_json(const char *group_name
, gid_t gid
, const char *description
, sd_json_variant
**ret
) {
214 assert(gid_is_valid(gid
));
217 return sd_json_buildo(
219 SD_JSON_BUILD_PAIR("record", SD_JSON_BUILD_OBJECT(
220 SD_JSON_BUILD_PAIR("groupName", SD_JSON_BUILD_STRING(group_name
)),
221 SD_JSON_BUILD_PAIR("gid", SD_JSON_BUILD_UNSIGNED(gid
)),
222 SD_JSON_BUILD_PAIR_CONDITION(!isempty(description
), "description", SD_JSON_BUILD_STRING(description
)),
223 SD_JSON_BUILD_PAIR("service", JSON_BUILD_CONST_STRING("io.systemd.Machine")),
224 SD_JSON_BUILD_PAIR("disposition", JSON_BUILD_CONST_STRING("container")))));
227 static bool group_match_lookup_parameters(LookupParameters
*p
, const char *name
, gid_t gid
) {
230 if (p
->group_name
&& !streq(name
, p
->group_name
))
233 if (gid_is_valid(p
->gid
) && gid
!= p
->gid
)
239 static int group_lookup_gid(Manager
*m
, gid_t gid
, char **ret_name
, char **ret_description
) {
240 _cleanup_free_
char *n
= NULL
, *d
= NULL
;
246 assert(gid_is_valid(gid
));
248 assert(ret_description
);
250 if (gid
< 0x10000) /* Host GID range */
253 r
= manager_find_machine_for_gid(m
, gid
, &machine
, &converted_gid
);
259 if (asprintf(&n
, "vg-%s-" GID_FMT
, machine
->name
, converted_gid
) < 0)
262 if (!valid_user_group_name(n
, 0))
265 if (asprintf(&d
, "GID " GID_FMT
" of Container %s", converted_gid
, machine
->name
) < 0)
270 *ret_name
= TAKE_PTR(n
);
271 *ret_description
= TAKE_PTR(d
);
276 static int group_lookup_name(Manager
*m
, const char *name
, gid_t
*ret_gid
, char **ret_description
) {
277 _cleanup_free_
char *mn
= NULL
, *desc
= NULL
;
278 gid_t gid
, converted_gid
;
285 assert(ret_description
);
287 if (!valid_user_group_name(name
, 0))
290 e
= startswith(name
, "vg-");
298 if (parse_gid(d
+ 1, &gid
) < 0)
301 mn
= strndup(e
, d
- e
);
305 machine
= hashmap_get(m
->machines
, mn
);
309 if (machine
->class != MACHINE_CONTAINER
)
312 r
= machine_translate_gid(machine
, gid
, &converted_gid
);
316 if (asprintf(&desc
, "GID " GID_FMT
" of Container %s", gid
, machine
->name
) < 0)
318 if (!valid_gecos(desc
))
321 *ret_gid
= converted_gid
;
322 *ret_description
= TAKE_PTR(desc
);
326 static int vl_method_get_group_record(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
328 static const sd_json_dispatch_field dispatch_table
[] = {
329 { "gid", SD_JSON_VARIANT_UNSIGNED
, sd_json_dispatch_uid_gid
, offsetof(LookupParameters
, gid
), 0 },
330 { "groupName", SD_JSON_VARIANT_STRING
, json_dispatch_const_user_group_name
, offsetof(LookupParameters
, group_name
), SD_JSON_RELAX
},
331 { "service", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(LookupParameters
, service
), 0 },
335 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
;
336 LookupParameters p
= {
339 _cleanup_free_
char *found_name
= NULL
, *found_description
= NULL
;
340 uid_t found_gid
= GID_INVALID
, gid
;
341 Manager
*m
= ASSERT_PTR(userdata
);
347 r
= sd_varlink_dispatch(link
, parameters
, dispatch_table
, &p
);
351 if (!streq_ptr(p
.service
, "io.systemd.Machine"))
352 return sd_varlink_error(link
, "io.systemd.UserDatabase.BadService", NULL
);
354 if (gid_is_valid(p
.gid
))
355 r
= group_lookup_gid(m
, p
.gid
, &found_name
, &found_description
);
356 else if (p
.group_name
)
357 r
= group_lookup_name(m
, p
.group_name
, (uid_t
*) &found_gid
, &found_description
);
359 return sd_varlink_error(link
, "io.systemd.UserDatabase.EnumerationNotSupported", NULL
);
361 return sd_varlink_error(link
, "io.systemd.UserDatabase.NoRecordFound", NULL
);
365 gid
= gid_is_valid(found_gid
) ? found_gid
: p
.gid
;
366 gn
= found_name
?: p
.group_name
;
368 if (!group_match_lookup_parameters(&p
, gn
, gid
))
369 return sd_varlink_error(link
, "io.systemd.UserDatabase.ConflictingRecordFound", NULL
);
371 r
= build_group_json(gn
, gid
, found_description
, &v
);
375 return sd_varlink_reply(link
, v
);
378 static int vl_method_get_memberships(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
380 static const sd_json_dispatch_field dispatch_table
[] = {
381 { "userName", SD_JSON_VARIANT_STRING
, json_dispatch_const_user_group_name
, offsetof(LookupParameters
, user_name
), SD_JSON_RELAX
},
382 { "groupName", SD_JSON_VARIANT_STRING
, json_dispatch_const_user_group_name
, offsetof(LookupParameters
, group_name
), SD_JSON_RELAX
},
383 { "service", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(LookupParameters
, service
), 0 },
387 LookupParameters p
= {};
392 r
= sd_varlink_dispatch(link
, parameters
, dispatch_table
, &p
);
396 if (!streq_ptr(p
.service
, "io.systemd.Machine"))
397 return sd_varlink_error(link
, "io.systemd.UserDatabase.BadService", NULL
);
399 /* We don't support auxiliary groups for machines. */
400 return sd_varlink_error(link
, "io.systemd.UserDatabase.NoRecordFound", NULL
);
403 static int json_build_local_addresses(const struct local_address
*addresses
, size_t n_addresses
, sd_json_variant
**ret
) {
404 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*array
= NULL
;
407 assert(addresses
|| n_addresses
== 0);
410 FOREACH_ARRAY(a
, addresses
, n_addresses
) {
411 r
= sd_json_variant_append_arraybo(
413 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("ifindex", a
->ifindex
),
414 SD_JSON_BUILD_PAIR_INTEGER("family", a
->family
),
415 SD_JSON_BUILD_PAIR_BYTE_ARRAY("address", &a
->address
.bytes
, FAMILY_ADDRESS_SIZE(a
->family
)));
420 *ret
= TAKE_PTR(array
);
424 static int list_machine_one_and_maybe_read_metadata(sd_varlink
*link
, Machine
*m
, bool more
, AcquireMetadata am
) {
425 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
, *addr_array
= NULL
;
426 _cleanup_strv_free_
char **os_release
= NULL
;
427 uid_t shift
= UID_INVALID
;
433 if (should_acquire_metadata(am
)) {
434 _cleanup_free_
struct local_address
*addresses
= NULL
;
436 r
= machine_get_addresses(m
, &addresses
);
437 if (r
< 0 && am
== ACQUIRE_METADATA_GRACEFUL
)
438 log_debug_errno(r
, "Failed to get address (graceful mode), ignoring: %m");
439 else if (r
== -ENONET
)
440 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NO_PRIVATE_NETWORKING
, NULL
);
441 else if (ERRNO_IS_NEG_NOT_SUPPORTED(r
))
442 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NOT_AVAILABLE
, NULL
);
444 return log_debug_errno(r
, "Failed to get addresses: %m");
446 r
= json_build_local_addresses(addresses
, r
, &addr_array
);
451 r
= machine_get_os_release(m
, &os_release
);
452 if (r
< 0 && am
== ACQUIRE_METADATA_GRACEFUL
)
453 log_debug_errno(r
, "Failed to get OS release (graceful mode), ignoring: %m");
454 else if (r
== -ENONET
)
455 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NO_OS_RELEASE_INFORMATION
, NULL
);
456 else if (ERRNO_IS_NEG_NOT_SUPPORTED(r
))
457 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NOT_AVAILABLE
, NULL
);
459 return log_debug_errno(r
, "Failed to get OS release: %m");
461 r
= machine_get_uid_shift(m
, &shift
);
462 if (r
< 0 && am
== ACQUIRE_METADATA_GRACEFUL
)
463 log_debug_errno(r
, "Failed to get UID shift (graceful mode), ignoring: %m");
464 else if (r
== -ENXIO
)
465 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NO_UID_SHIFT
, NULL
);
466 else if (ERRNO_IS_NEG_NOT_SUPPORTED(r
))
467 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NOT_AVAILABLE
, NULL
);
469 return log_debug_errno(r
, "Failed to get UID shift: %m");
474 SD_JSON_BUILD_PAIR("name", SD_JSON_BUILD_STRING(m
->name
)),
475 SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m
->id
), "id", SD_JSON_BUILD_ID128(m
->id
)),
476 SD_JSON_BUILD_PAIR("class", SD_JSON_BUILD_STRING(machine_class_to_string(m
->class))),
477 JSON_BUILD_PAIR_STRING_NON_EMPTY("service", m
->service
),
478 JSON_BUILD_PAIR_STRING_NON_EMPTY("rootDirectory", m
->root_directory
),
479 JSON_BUILD_PAIR_STRING_NON_EMPTY("unit", m
->unit
),
480 JSON_BUILD_PAIR_STRING_NON_EMPTY("subgroup", m
->subgroup
),
481 SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&m
->leader
), "leader", JSON_BUILD_PIDREF(&m
->leader
)),
482 SD_JSON_BUILD_PAIR_CONDITION(pidref_is_set(&m
->supervisor
), "supervisor", JSON_BUILD_PIDREF(&m
->supervisor
)),
483 SD_JSON_BUILD_PAIR_CONDITION(dual_timestamp_is_set(&m
->timestamp
), "timestamp", JSON_BUILD_DUAL_TIMESTAMP(&m
->timestamp
)),
484 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("vSockCid", m
->vsock_cid
, VMADDR_CID_ANY
),
485 JSON_BUILD_PAIR_STRING_NON_EMPTY("sshAddress", m
->ssh_address
),
486 JSON_BUILD_PAIR_STRING_NON_EMPTY("sshPrivateKeyPath", m
->ssh_private_key_path
),
487 JSON_BUILD_PAIR_VARIANT_NON_NULL("addresses", addr_array
),
488 JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("OSRelease", os_release
),
489 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("UIDShift", shift
, UID_INVALID
),
490 SD_JSON_BUILD_PAIR_UNSIGNED("UID", m
->uid
));
495 return sd_varlink_notify(link
, v
);
497 return sd_varlink_reply(link
, v
);
500 typedef struct MachineLookupParameters
{
503 AcquireMetadata acquire_metadata
;
504 } MachineLookupParameters
;
506 static void machine_lookup_parameters_done(MachineLookupParameters
*p
) {
509 pidref_done(&p
->pidref
);
512 static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_acquire_metadata
, AcquireMetadata
, acquire_metadata_from_string
);
514 static int vl_method_list(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
515 static const sd_json_dispatch_field dispatch_table
[] = {
516 VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(MachineLookupParameters
),
517 { "acquireMetadata", SD_JSON_VARIANT_STRING
, json_dispatch_acquire_metadata
, offsetof(MachineLookupParameters
, acquire_metadata
), 0 },
518 VARLINK_DISPATCH_POLKIT_FIELD
,
522 Manager
*m
= ASSERT_PTR(userdata
);
523 _cleanup_(machine_lookup_parameters_done
) MachineLookupParameters p
= {
524 .pidref
= PIDREF_NULL
,
533 r
= sd_varlink_dispatch(link
, parameters
, dispatch_table
, &p
);
537 if (p
.name
|| pidref_is_set(&p
.pidref
) || pidref_is_automatic(&p
.pidref
)) {
538 r
= lookup_machine_by_name_or_pidref(link
, m
, p
.name
, &p
.pidref
, &machine
);
540 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE
, NULL
);
544 return list_machine_one_and_maybe_read_metadata(link
, machine
, /* more = */ false, p
.acquire_metadata
);
547 if (!FLAGS_SET(flags
, SD_VARLINK_METHOD_MORE
))
548 return sd_varlink_error(link
, SD_VARLINK_ERROR_EXPECTED_MORE
, NULL
);
550 Machine
*previous
= NULL
, *i
;
551 HASHMAP_FOREACH(i
, m
->machines
) {
553 r
= list_machine_one_and_maybe_read_metadata(link
, previous
, /* more = */ true, p
.acquire_metadata
);
562 return list_machine_one_and_maybe_read_metadata(link
, previous
, /* more = */ false, p
.acquire_metadata
);
564 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE
, NULL
);
567 static int lookup_machine_and_call_method(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
, sd_varlink_method_t method
) {
568 static const sd_json_dispatch_field dispatch_table
[] = {
569 VARLINK_DISPATCH_MACHINE_LOOKUP_FIELDS(MachineLookupParameters
),
570 VARLINK_DISPATCH_POLKIT_FIELD
,
574 Manager
*manager
= ASSERT_PTR(userdata
);
575 _cleanup_(machine_lookup_parameters_done
) MachineLookupParameters p
= {
576 .pidref
= PIDREF_NULL
,
584 r
= sd_varlink_dispatch(link
, parameters
, dispatch_table
, &p
);
588 r
= lookup_machine_by_name_or_pidref(link
, manager
, p
.name
, &p
.pidref
, &machine
);
590 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_NO_SUCH_MACHINE
, NULL
);
594 return method(link
, parameters
, flags
, machine
);
597 static int vl_method_unregister(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
598 return lookup_machine_and_call_method(link
, parameters
, flags
, userdata
, vl_method_unregister_internal
);
601 static int vl_method_terminate(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
602 return lookup_machine_and_call_method(link
, parameters
, flags
, userdata
, vl_method_terminate_internal
);
605 static int vl_method_copy_from(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
606 return vl_method_copy_internal(link
, parameters
, flags
, userdata
, /* copy_from = */ true);
609 static int vl_method_copy_to(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
610 return vl_method_copy_internal(link
, parameters
, flags
, userdata
, /* copy_from = */ false);
613 static int vl_method_open_root_directory(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
614 return lookup_machine_and_call_method(link
, parameters
, flags
, userdata
, vl_method_open_root_directory_internal
);
617 static int list_image_one_and_maybe_read_metadata(sd_varlink
*link
, Image
*image
, bool more
, AcquireMetadata am
) {
623 if (should_acquire_metadata(am
) && !image
->metadata_valid
) {
624 r
= image_read_metadata(image
, &image_policy_container
);
625 if (r
< 0 && am
!= ACQUIRE_METADATA_GRACEFUL
)
626 return log_debug_errno(r
, "Failed to read image metadata: %m");
628 log_debug_errno(r
, "Failed to read image metadata (graceful mode), ignoring: %m");
631 _cleanup_(sd_json_variant_unrefp
) sd_json_variant
*v
= NULL
;
635 SD_JSON_BUILD_PAIR_STRING("name", image
->name
),
636 JSON_BUILD_PAIR_STRING_NON_EMPTY("path", image
->path
),
637 SD_JSON_BUILD_PAIR_STRING("type", image_type_to_string(image
->type
)),
638 SD_JSON_BUILD_PAIR_STRING("class", image_class_to_string(image
->class)),
639 SD_JSON_BUILD_PAIR_BOOLEAN("readOnly", image
->read_only
),
640 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("creationTimestamp", image
->crtime
),
641 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("modificationTimestamp", image
->mtime
),
642 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("usage", image
->usage
, UINT64_MAX
),
643 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("usageExclusive", image
->usage_exclusive
, UINT64_MAX
),
644 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("limit", image
->limit
, UINT64_MAX
),
645 JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("limitExclusive", image
->limit_exclusive
, UINT64_MAX
));
649 if (should_acquire_metadata(am
) && image
->metadata_valid
) {
650 r
= sd_json_variant_merge_objectbo(
652 JSON_BUILD_PAIR_STRING_NON_EMPTY("hostname", image
->hostname
),
653 SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(image
->machine_id
), "machineId", SD_JSON_BUILD_ID128(image
->machine_id
)),
654 JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("machineInfo", image
->machine_info
),
655 JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("OSRelease", image
->os_release
));
661 return sd_varlink_notify(link
, v
);
663 return sd_varlink_reply(link
, v
);
666 static int vl_method_list_images(sd_varlink
*link
, sd_json_variant
*parameters
, sd_varlink_method_flags_t flags
, void *userdata
) {
667 Manager
*m
= ASSERT_PTR(userdata
);
669 const char *image_name
;
670 AcquireMetadata acquire_metadata
;
674 static const sd_json_dispatch_field dispatch_table
[] = {
675 { "name", SD_JSON_VARIANT_STRING
, sd_json_dispatch_const_string
, offsetof(struct params
, image_name
), 0 },
676 { "acquireMetadata", SD_JSON_VARIANT_STRING
, json_dispatch_acquire_metadata
, offsetof(struct params
, acquire_metadata
), 0 },
677 VARLINK_DISPATCH_POLKIT_FIELD
,
684 r
= sd_varlink_dispatch(link
, parameters
, dispatch_table
, &p
);
689 _cleanup_(image_unrefp
) Image
*found
= NULL
;
691 if (!image_name_is_valid(p
.image_name
))
692 return sd_varlink_error_invalid_parameter_name(link
, "name");
694 r
= image_find(m
->runtime_scope
, IMAGE_MACHINE
, p
.image_name
, /* root = */ NULL
, &found
);
696 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE
, NULL
);
698 return log_debug_errno(r
, "Failed to find image: %m");
700 return list_image_one_and_maybe_read_metadata(link
, found
, /* more = */ false, p
.acquire_metadata
);
703 if (!FLAGS_SET(flags
, SD_VARLINK_METHOD_MORE
))
704 return sd_varlink_error(link
, SD_VARLINK_ERROR_EXPECTED_MORE
, NULL
);
706 _cleanup_hashmap_free_ Hashmap
*images
= NULL
;
707 r
= image_discover(m
->runtime_scope
, IMAGE_MACHINE
, /* root = */ NULL
, &images
);
709 return log_debug_errno(r
, "Failed to discover images: %m");
711 Image
*image
, *previous
= NULL
;
712 HASHMAP_FOREACH(image
, images
) {
714 r
= list_image_one_and_maybe_read_metadata(link
, previous
, /* more = */ true, p
.acquire_metadata
);
723 return list_image_one_and_maybe_read_metadata(link
, previous
, /* more = */ false, p
.acquire_metadata
);
725 return sd_varlink_error(link
, VARLINK_ERROR_MACHINE_IMAGE_NO_SUCH_IMAGE
, NULL
);
728 static int manager_varlink_init_userdb(Manager
*m
) {
729 _cleanup_(sd_varlink_server_unrefp
) sd_varlink_server
*s
= NULL
;
734 if (m
->varlink_userdb_server
)
737 r
= varlink_server_new(&s
, SD_VARLINK_SERVER_ACCOUNT_UID
|SD_VARLINK_SERVER_INHERIT_USERDATA
, m
);
739 return log_error_errno(r
, "Failed to allocate varlink server object: %m");
741 r
= sd_varlink_server_add_interface(s
, &vl_interface_io_systemd_UserDatabase
);
743 return log_error_errno(r
, "Failed to add UserDatabase interface to varlink server: %m");
745 r
= sd_varlink_server_bind_method_many(
747 "io.systemd.UserDatabase.GetUserRecord", vl_method_get_user_record
,
748 "io.systemd.UserDatabase.GetGroupRecord", vl_method_get_group_record
,
749 "io.systemd.UserDatabase.GetMemberships", vl_method_get_memberships
);
751 return log_error_errno(r
, "Failed to register varlink methods: %m");
753 r
= sd_varlink_server_listen_address(s
, "/run/systemd/userdb/io.systemd.Machine", 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755
);
755 return log_error_errno(r
, "Failed to bind to varlink socket: %m");
757 r
= sd_varlink_server_attach_event(s
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
759 return log_error_errno(r
, "Failed to attach varlink connection to event loop: %m");
761 m
->varlink_userdb_server
= TAKE_PTR(s
);
765 static int manager_varlink_init_machine(Manager
*m
) {
766 _cleanup_(sd_varlink_server_unrefp
) sd_varlink_server
*s
= NULL
;
771 if (m
->varlink_machine_server
)
774 r
= varlink_server_new(
776 SD_VARLINK_SERVER_ACCOUNT_UID
|SD_VARLINK_SERVER_INHERIT_USERDATA
|
777 SD_VARLINK_SERVER_ALLOW_FD_PASSING_OUTPUT
,
780 return log_error_errno(r
, "Failed to allocate varlink server object: %m");
782 r
= sd_varlink_server_add_interface_many(
784 &vl_interface_io_systemd_Machine
,
785 &vl_interface_io_systemd_MachineImage
,
786 &vl_interface_io_systemd_service
);
788 return log_error_errno(r
, "Failed to add Machine and MachineImage interfaces to varlink server: %m");
790 r
= sd_varlink_server_bind_method_many(
792 "io.systemd.Machine.Register", vl_method_register
,
793 "io.systemd.Machine.List", vl_method_list
,
794 "io.systemd.Machine.Unregister", vl_method_unregister
,
795 "io.systemd.Machine.Terminate", vl_method_terminate
,
796 "io.systemd.Machine.Kill", vl_method_kill
,
797 "io.systemd.Machine.Open", vl_method_open
,
798 "io.systemd.Machine.OpenRootDirectory", vl_method_open_root_directory
,
799 "io.systemd.Machine.MapFrom", vl_method_map_from
,
800 "io.systemd.Machine.MapTo", vl_method_map_to
,
801 "io.systemd.Machine.BindMount", vl_method_bind_mount
,
802 "io.systemd.Machine.CopyFrom", vl_method_copy_from
,
803 "io.systemd.Machine.CopyTo", vl_method_copy_to
,
804 "io.systemd.MachineImage.List", vl_method_list_images
,
805 "io.systemd.MachineImage.Update", vl_method_update_image
,
806 "io.systemd.MachineImage.Clone", vl_method_clone_image
,
807 "io.systemd.MachineImage.Remove", vl_method_remove_image
,
808 "io.systemd.MachineImage.SetPoolLimit", vl_method_set_pool_limit
,
809 "io.systemd.MachineImage.CleanPool", vl_method_clean_pool
,
810 "io.systemd.service.Ping", varlink_method_ping
,
811 "io.systemd.service.SetLogLevel", varlink_method_set_log_level
,
812 "io.systemd.service.GetEnvironment", varlink_method_get_environment
);
814 return log_error_errno(r
, "Failed to register varlink methods: %m");
816 r
= sd_varlink_server_listen_auto(s
);
818 return log_error_errno(r
, "Failed to bind to passed Varlink sockets: %m");
820 r
= sd_varlink_server_listen_address(s
, "/run/systemd/machine/io.systemd.Machine", 0666 | SD_VARLINK_SERVER_MODE_MKDIR_0755
);
822 return log_error_errno(r
, "Failed to bind to io.systemd.Machine varlink socket: %m");
824 r
= sd_varlink_server_listen_address(s
, "/run/systemd/machine/io.systemd.MachineImage", 0666);
826 return log_error_errno(r
, "Failed to bind to io.systemd.MachineImage varlink socket: %m");
829 r
= sd_varlink_server_attach_event(s
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
831 return log_error_errno(r
, "Failed to attach varlink connection to event loop: %m");
833 m
->varlink_machine_server
= TAKE_PTR(s
);
837 int manager_varlink_init(Manager
*m
) {
840 r
= manager_varlink_init_userdb(m
);
844 r
= manager_varlink_init_machine(m
);
851 void manager_varlink_done(Manager
*m
) {
854 m
->varlink_userdb_server
= sd_varlink_server_unref(m
->varlink_userdb_server
);
855 m
->varlink_machine_server
= sd_varlink_server_unref(m
->varlink_machine_server
);