diff --git a/man/org.freedesktop.machine1.xml b/man/org.freedesktop.machine1.xml index ea3a706215..c52aed0dbc 100644 --- a/man/org.freedesktop.machine1.xml +++ b/man/org.freedesktop.machine1.xml @@ -525,6 +525,8 @@ node /org/freedesktop/machine1/machine/rawhide { readonly s SSHPrivateKeyPath = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("false") readonly s State = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly u UID = ...; }; interface org.freedesktop.DBus.Peer { ... }; interface org.freedesktop.DBus.Introspectable { ... }; @@ -620,6 +622,8 @@ node /org/freedesktop/machine1/machine/rawhide { + + @@ -683,6 +687,8 @@ node /org/freedesktop/machine1/machine/rawhide { Subgroup contains the sub-control-group path this machine's processes reside in, relative to the specified unit's control group. + + UID contains the numeric UNIX UID of the user who registered the machine. @@ -726,7 +732,8 @@ $ gdbus introspect --system \ CopyToWithFlags() were added in version 252. GetSSHInfo(), VSockCID, SSHAddress, and SSHPrivateKeyPath were added in version 256. - LeaderPIDFDId and Subgroup were added in version 258. + LeaderPIDFDId, Subgroup, and UID were + added in version 258. diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index 8935b59465..321ddbfdcc 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -60,10 +60,12 @@ int bus_machine_method_unregister(sd_bus_message *message, void *userdata, sd_bu NULL }; - r = bus_verify_polkit_async( + r = bus_verify_polkit_async_full( message, "org.freedesktop.machine1.manage-machines", details, + m->uid, + /* flags= */ 0, &m->manager->polkit_registry, error); if (r < 0) @@ -90,10 +92,12 @@ int bus_machine_method_terminate(sd_bus_message *message, void *userdata, sd_bus NULL }; - r = bus_verify_polkit_async( + r = bus_verify_polkit_async_full( message, "org.freedesktop.machine1.manage-machines", details, + m->uid, + /* flags= */ 0, &m->manager->polkit_registry, error); if (r < 0) @@ -138,10 +142,12 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro NULL }; - r = bus_verify_polkit_async( + r = bus_verify_polkit_async_full( message, "org.freedesktop.machine1.manage-machines", details, + m->uid, + /* flags= */ 0, &m->manager->polkit_registry, error); if (r < 0) @@ -258,10 +264,12 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_ NULL }; - r = bus_verify_polkit_async( + r = bus_verify_polkit_async_full( message, m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty", details, + m->uid, + /* flags= */ 0, &m->manager->polkit_registry, error); if (r < 0) @@ -299,10 +307,12 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu NULL }; - r = bus_verify_polkit_async( + r = bus_verify_polkit_async_full( message, m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login", details, + m->uid, + /* flags= */ 0, &m->manager->polkit_registry, error); if (r < 0) @@ -383,10 +393,12 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu NULL }; - r = bus_verify_polkit_async( + r = bus_verify_polkit_async_full( message, m->class == MACHINE_HOST ? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell", details, + m->uid, + /* flags= */ 0, &m->manager->polkit_registry, error); if (r < 0) @@ -446,6 +458,7 @@ int bus_machine_method_bind_mount(sd_bus_message *message, void *userdata, sd_bu NULL }; + /* NB: For now not opened up to owner of machine without auth */ r = bus_verify_polkit_async( message, "org.freedesktop.machine1.manage-machines", @@ -531,6 +544,7 @@ int bus_machine_method_copy(sd_bus_message *message, void *userdata, sd_bus_erro NULL }; + /* NB: For now not opened up to owner of machine without auth */ r = bus_verify_polkit_async( message, "org.freedesktop.machine1.manage-machines", @@ -574,6 +588,7 @@ int bus_machine_method_open_root_directory(sd_bus_message *message, void *userda NULL }; + /* NB: For now not opened up to owner of machine without auth */ r = bus_verify_polkit_async( message, "org.freedesktop.machine1.manage-machines", @@ -727,6 +742,7 @@ static const sd_bus_vtable machine_vtable[] = { SD_BUS_PROPERTY("SSHAddress", "s", NULL, offsetof(Machine, ssh_address), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("SSHPrivateKeyPath", "s", NULL, offsetof(Machine, ssh_private_key_path), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0), + SD_BUS_PROPERTY("UID", "u", bus_property_get_uid, offsetof(Machine, uid), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_METHOD("Terminate", NULL, diff --git a/src/machine/machine-varlink.c b/src/machine/machine-varlink.c index b5754e2c49..8c437efc17 100644 --- a/src/machine/machine-varlink.c +++ b/src/machine/machine-varlink.c @@ -168,6 +168,10 @@ int vl_method_register(sd_varlink *link, sd_json_variant *parameters, sd_varlink return r; } + r = sd_varlink_get_peer_uid(link, &machine->uid); + if (r < 0) + return r; + r = machine_link(manager, machine); if (r == -EEXIST) return sd_varlink_error(link, VARLINK_ERROR_MACHINE_EXISTS, NULL); @@ -278,12 +282,14 @@ int vl_method_unregister_internal(sd_varlink *link, sd_json_variant *parameters, Manager *manager = ASSERT_PTR(machine->manager); int r; - r = varlink_verify_polkit_async( + r = varlink_verify_polkit_async_full( link, manager->bus, "org.freedesktop.machine1.manage-machines", (const char**) STRV_MAKE("name", machine->name, "verb", "unregister"), + machine->uid, + /* flags= */ 0, &manager->polkit_registry); if (r <= 0) return r; @@ -300,12 +306,14 @@ int vl_method_terminate_internal(sd_varlink *link, sd_json_variant *parameters, Manager *manager = ASSERT_PTR(machine->manager); int r; - r = varlink_verify_polkit_async( + r = varlink_verify_polkit_async_full( link, manager->bus, "org.freedesktop.machine1.manage-machines", (const char**) STRV_MAKE("name", machine->name, "verb", "terminate"), + machine->uid, + /* flags= */ 0, &manager->polkit_registry); if (r <= 0) return r; @@ -368,12 +376,14 @@ int vl_method_kill(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met return sd_varlink_error_invalid_parameter_name(link, "whom"); } - r = varlink_verify_polkit_async( + r = varlink_verify_polkit_async_full( link, manager->bus, "org.freedesktop.machine1.manage-machines", (const char**) STRV_MAKE("name", machine->name, "verb", "kill"), + machine->uid, + /* flags= */ 0, &manager->polkit_registry); if (r <= 0) return r; @@ -510,11 +520,13 @@ int vl_method_open(sd_varlink *link, sd_json_variant *parameters, sd_varlink_met return r; polkit_details = machine_open_polkit_details(p.mode, machine->name, user, path, command_line); - r = varlink_verify_polkit_async( + r = varlink_verify_polkit_async_full( link, manager->bus, machine_open_polkit_action(p.mode, machine->class), (const char**) polkit_details, + machine->uid, + /* flags= */ 0, &manager->polkit_registry); if (r <= 0) return r; @@ -788,6 +800,7 @@ int vl_method_bind_mount(sd_varlink *link, sd_json_variant *parameters, sd_varli if (machine->class != MACHINE_CONTAINER) return sd_varlink_error(link, VARLINK_ERROR_MACHINE_NOT_SUPPORTED, NULL); + /* NB: For now not opened up to owner of machine without auth */ r = varlink_verify_polkit_async( link, manager->bus, @@ -899,6 +912,7 @@ int vl_method_copy_internal(sd_varlink *link, sd_json_variant *parameters, sd_va if (machine->class != MACHINE_CONTAINER) return sd_varlink_error(link, VARLINK_ERROR_MACHINE_NOT_SUPPORTED, NULL); + /* NB: For now not opened up to owner of machine without auth */ r = varlink_verify_polkit_async( link, manager->bus, @@ -928,6 +942,7 @@ int vl_method_open_root_directory_internal(sd_varlink *link, sd_json_variant *pa Manager *manager = ASSERT_PTR(machine->manager); int r; + /* NB: For now not opened up to owner of machine without auth */ r = varlink_verify_polkit_async( link, manager->bus, diff --git a/src/machine/machine.c b/src/machine/machine.c index 7ce512dd62..91c1450184 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -183,8 +183,10 @@ int machine_save(Machine *m) { fprintf(f, "# This is private data. Do not parse.\n" - "NAME=%s\n", - m->name); + "NAME=%s\n" + "UID=" UID_FMT "\n", + m->name, + m->uid); /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */ env_file_fputs_assignment(f, "SCOPE=", m->unit); @@ -261,7 +263,7 @@ static void machine_unlink(Machine *m) { int machine_load(Machine *m) { _cleanup_free_ char *name = NULL, *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *leader_pidfdid = NULL, - *class = NULL, *netif = NULL, *vsock_cid = NULL; + *class = NULL, *netif = NULL, *vsock_cid = NULL, *uid = NULL; int r; assert(m); @@ -285,7 +287,8 @@ int machine_load(Machine *m) { "NETIF", &netif, "VSOCK_CID", &vsock_cid, "SSH_ADDRESS", &m->ssh_address, - "SSH_PRIVATE_KEY_PATH", &m->ssh_private_key_path); + "SSH_PRIVATE_KEY_PATH", &m->ssh_private_key_path, + "UID", &uid); if (r == -ENOENT) return 0; if (r < 0) @@ -369,6 +372,10 @@ int machine_load(Machine *m) { log_warning_errno(r, "Failed to parse AF_VSOCK CID, ignoring: %s", vsock_cid); } + r = parse_uid(uid, &m->uid); + if (r < 0) + log_warning_errno(r, "Failed to parse owning UID, ignoring: %s", uid); + return r; } @@ -426,14 +433,28 @@ static int machine_start_scope( if (r < 0) return r; - r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)", - "Delegate", "b", 1, - "CollectMode", "s", "inactive-or-failed", - "AddRef", "b", 1, - "TasksMax", "t", UINT64_C(16384)); + r = sd_bus_message_append( + m, "(sv)(sv)(sv)(sv)", + "Delegate", "b", 1, + "CollectMode", "s", "inactive-or-failed", + "AddRef", "b", 1, + "TasksMax", "t", UINT64_C(16384)); if (r < 0) return r; + if (machine->uid != 0) { + _cleanup_free_ char *u = NULL; + + if (asprintf(&u, UID_FMT, machine->uid) < 0) + return -ENOMEM; + + r = sd_bus_message_append( + m, "(sv)", + "User", "s", u); + if (r < 0) + return r; + } + if (more_properties) { r = sd_bus_message_copy(m, more_properties, true); if (r < 0) diff --git a/src/machine/machine.h b/src/machine/machine.h index 8762263a8b..dddc0c8000 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -38,6 +38,8 @@ typedef struct Machine { char *name; sd_id128_t id; + uid_t uid; + MachineClass class; char *state_file; diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 7731fae708..d31ef407f4 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -514,6 +514,7 @@ typedef struct MachineStatusInfo { struct dual_timestamp timestamp; int *netif; size_t n_netif; + uid_t uid; } MachineStatusInfo; static void machine_status_info_clear(MachineStatusInfo *info) { @@ -567,6 +568,9 @@ static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) { } else if (i->class) printf("\t Class: %s\n", i->class); + if (i->uid != 0) + printf("\t UID: " UID_FMT "\n", i->uid); + if (i->root_directory) printf("\t Root: %s\n", i->root_directory); @@ -662,6 +666,7 @@ static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bo { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) }, { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) }, { "NetworkInterfaces", "ai", map_netif, 0 }, + { "UID", "u", NULL, offsetof(MachineStatusInfo, uid) }, {} }; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 8aa00ba3ed..30f722a449 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -300,6 +300,16 @@ static int method_create_or_register_machine( if (hashmap_get(manager->machines, name)) return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name); + _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL; + r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_EUID, &creds); + if (r < 0) + return r; + + uid_t uid; + r = sd_bus_creds_get_euid(creds, &uid); + if (r < 0) + return r; + const char *details[] = { "name", name, "class", machine_class_to_string(c), @@ -324,6 +334,7 @@ static int method_create_or_register_machine( m->leader = TAKE_PIDREF(pidref); m->class = c; m->id = id; + m->uid = uid; if (!isempty(service)) { m->service = strdup(service); diff --git a/src/machine/machined-varlink.c b/src/machine/machined-varlink.c index 8551d703e7..7dac3cb0d2 100644 --- a/src/machine/machined-varlink.c +++ b/src/machine/machined-varlink.c @@ -485,7 +485,8 @@ static int list_machine_one_and_maybe_read_metadata(sd_varlink *link, Machine *m JSON_BUILD_PAIR_STRING_NON_EMPTY("sshPrivateKeyPath", m->ssh_private_key_path), JSON_BUILD_PAIR_VARIANT_NON_NULL("addresses", addr_array), JSON_BUILD_PAIR_STRV_ENV_PAIR_NON_EMPTY("OSRelease", os_release), - JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("UIDShift", shift, UID_INVALID)); + JSON_BUILD_PAIR_UNSIGNED_NOT_EQUAL("UIDShift", shift, UID_INVALID), + SD_JSON_BUILD_PAIR_UNSIGNED("UID", m->uid)); if (r < 0) return r; diff --git a/src/shared/varlink-io.systemd.Machine.c b/src/shared/varlink-io.systemd.Machine.c index 1bb7c00fa1..ad7dff228f 100644 --- a/src/shared/varlink-io.systemd.Machine.c +++ b/src/shared/varlink-io.systemd.Machine.c @@ -98,7 +98,9 @@ static SD_VARLINK_DEFINE_METHOD_FULL( SD_VARLINK_FIELD_COMMENT("Return the base UID/GID of the machine"), SD_VARLINK_DEFINE_OUTPUT(UIDShift, SD_VARLINK_INT, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Subcgroup path of the machine, relative to the unit's cgroup path"), - SD_VARLINK_DEFINE_OUTPUT(Subgroup, SD_VARLINK_STRING, SD_VARLINK_NULLABLE)); + SD_VARLINK_DEFINE_OUTPUT(Subgroup, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("Numeric UNIX UID of the user who registered the machine"), + SD_VARLINK_DEFINE_OUTPUT(UID, SD_VARLINK_INT, SD_VARLINK_NULLABLE)); static SD_VARLINK_DEFINE_ENUM_TYPE( MachineOpenMode,