Compare commits

..

10 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek b596ef81b6
Merge ed0c57c6da into 52b0351a15 2024-11-20 09:37:38 +01:00
Zbigniew Jędrzejewski-Szmek ed0c57c6da gpt-auto-generator: improve log message
We said "exiting", but then the program continues to do other operations
and log additional messages.
2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek 0f99304e11 shared/exec-util: fix logging of the args of an executed program
The debug logs has lots of "About to execute /some/path (null)". This
occurs when the args array is empty. Instead, only print "(null)" if
we failed with oom.

Having strv_skip() return NULL makes this pleasant to write without repeating
strv_isempty() a few times.
2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek ee0d84bff6 test-execve: minor simplification 2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek 14ded07623 various: handle the positive condition after strv_skip() first 2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek 7764746336 busctl: use RET_GATHER 2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek 17d702393b busctl: use STRV_FOREACH in the usual fashion
Also put positive branch first, do not use 'i' as a char** variable name.
2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek a573879ac1 analyze: use STRV_FOREACH in consistent fashion
Also put positive condition first.
2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek e30467cea0 basic/strv: return NULL from strv_skip
strv_skip was written to carefully return the original array, but this turns
out to be an unnecessary complication. After the previous patch, no caller
cares about the distinction between NULL and { NULL }, but various callers need
to wrap the process the returned value with strv_isempty(), sometimes more than
once. Let's always return NULL for an empty result to allow callers to be
simplified.
2024-11-19 17:18:14 +01:00
Zbigniew Jędrzejewski-Szmek 5fb5bbfdea homectl: do not rely on strv_skip() returning an empty list
mangle_user_list() was doing a microoptimization of avoiding of
copying of a single string by constructing the strv object manually.
This seems like more trouble than it's worth, considering that this
is called once in the program's life.

Simplify that code and always return an array constructed with strv_copy()
or strv_new().
2024-11-19 17:18:14 +01:00
6 changed files with 132 additions and 138 deletions

View File

@ -803,10 +803,6 @@ int cg_pid_get_path(const char *controller, pid_t pid, char **ret_path) {
if (!path) if (!path)
return -ENOMEM; return -ENOMEM;
/* Refuse cgroup paths from outside our cgroup namespace */
if (startswith(path, "/../"))
return -EUNATCH;
/* Truncate suffix indicating the process is a zombie */ /* Truncate suffix indicating the process is a zombie */
e = endswith(path, " (deleted)"); e = endswith(path, " (deleted)");
if (e) if (e)

View File

@ -102,8 +102,8 @@ int pid_get_comm(pid_t pid, char **ret) {
_cleanup_free_ char *escaped = NULL, *comm = NULL; _cleanup_free_ char *escaped = NULL, *comm = NULL;
int r; int r;
assert(pid >= 0);
assert(ret); assert(ret);
assert(pid >= 0);
if (pid == 0 || pid == getpid_cached()) { if (pid == 0 || pid == getpid_cached()) {
comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */ comm = new0(char, TASK_COMM_LEN + 1); /* Must fit in 16 byte according to prctl(2) */
@ -143,9 +143,6 @@ int pidref_get_comm(const PidRef *pid, char **ret) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_comm(pid->pid, &comm); r = pid_get_comm(pid->pid, &comm);
if (r < 0) if (r < 0)
return r; return r;
@ -292,9 +289,6 @@ int pidref_get_cmdline(const PidRef *pid, size_t max_columns, ProcessCmdlineFlag
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_cmdline(pid->pid, max_columns, flags, &s); r = pid_get_cmdline(pid->pid, max_columns, flags, &s);
if (r < 0) if (r < 0)
return r; return r;
@ -337,9 +331,6 @@ int pidref_get_cmdline_strv(const PidRef *pid, ProcessCmdlineFlags flags, char *
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_cmdline_strv(pid->pid, flags, &args); r = pid_get_cmdline_strv(pid->pid, flags, &args);
if (r < 0) if (r < 0)
return r; return r;
@ -486,9 +477,6 @@ int pidref_is_kernel_thread(const PidRef *pid) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
result = pid_is_kernel_thread(pid->pid); result = pid_is_kernel_thread(pid->pid);
if (result < 0) if (result < 0)
return result; return result;
@ -606,9 +594,6 @@ int pidref_get_uid(const PidRef *pid, uid_t *ret) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_uid(pid->pid, &uid); r = pid_get_uid(pid->pid, &uid);
if (r < 0) if (r < 0)
return r; return r;
@ -809,9 +794,6 @@ int pidref_get_start_time(const PidRef *pid, usec_t *ret) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
r = pid_get_start_time(pid->pid, ret ? &t : NULL); r = pid_get_start_time(pid->pid, ret ? &t : NULL);
if (r < 0) if (r < 0)
return r; return r;
@ -1111,9 +1093,6 @@ int pidref_is_my_child(const PidRef *pid) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
result = pid_is_my_child(pid->pid); result = pid_is_my_child(pid->pid);
if (result < 0) if (result < 0)
return result; return result;
@ -1149,9 +1128,6 @@ int pidref_is_unwaited(const PidRef *pid) {
if (!pidref_is_set(pid)) if (!pidref_is_set(pid))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pid))
return -EREMOTE;
if (pid->pid == 1 || pidref_is_self(pid)) if (pid->pid == 1 || pidref_is_self(pid))
return true; return true;
@ -1193,9 +1169,6 @@ int pidref_is_alive(const PidRef *pidref) {
if (!pidref_is_set(pidref)) if (!pidref_is_set(pidref))
return -ESRCH; return -ESRCH;
if (pidref_is_remote(pidref))
return -EREMOTE;
result = pid_is_alive(pidref->pid); result = pid_is_alive(pidref->pid);
if (result < 0) { if (result < 0) {
assert(result != -ESRCH); assert(result != -ESRCH);

View File

@ -193,7 +193,7 @@ int enroll_fido2(
fflush(stdout); fflush(stdout);
fprintf(stderr, fprintf(stderr,
"\nPlease save this FIDO2 credential ID. It is required when unlocking the volume\n" "\nPlease save this FIDO2 credential ID. It is required when unloocking the volume\n"
"using the associated FIDO2 keyslot which we just created. To configure automatic\n" "using the associated FIDO2 keyslot which we just created. To configure automatic\n"
"unlocking using this FIDO2 token, add an appropriate entry to your /etc/crypttab\n" "unlocking using this FIDO2 token, add an appropriate entry to your /etc/crypttab\n"
"file, see %s for details.\n", link); "file, see %s for details.\n", link);

View File

@ -691,51 +691,34 @@ static void dump_home_record(UserRecord *hr) {
} }
} }
static int inspect_home(sd_bus *bus, const char *name) { static int mangle_user_list(char **list, char ***ret) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; char **l;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_(user_record_unrefp) UserRecord *hr = NULL;
const char *json;
int incomplete;
uid_t uid;
int r;
r = parse_uid(name, &uid); if (strv_isempty(list)) {
if (r < 0) { _cleanup_free_ char *myself = NULL;
if (!valid_user_group_name(name, 0))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid user name '%s'.", name);
r = bus_call_method(bus, bus_mgr, "GetUserRecordByName", &error, &reply, "s", name); myself = getusername_malloc();
if (!myself)
return log_oom();
l = strv_new(myself);
} else } else
r = bus_call_method(bus, bus_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid); l = strv_copy(list);
if (r < 0) if (!l)
return log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
r = sd_bus_message_read(reply, "sbo", &json, &incomplete, NULL);
if (r < 0)
return bus_log_parse_error(r);
r = sd_json_parse(json, SD_JSON_PARSE_SENSITIVE, &v, NULL, NULL);
if (r < 0)
return log_error_errno(r, "Failed to parse JSON identity: %m");
hr = user_record_new();
if (!hr)
return log_oom(); return log_oom();
r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE); *ret = l;
if (r < 0)
return r;
hr->incomplete = incomplete;
dump_home_record(hr);
return 0; return 0;
} }
static int inspect_homes(int argc, char *argv[], void *userdata) { static int inspect_home(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r; _cleanup_strv_free_ char **items = NULL;
int r, ret = 0;
r = mangle_user_list(strv_skip(argv, 1), &items);
if (r < 0)
return r;
r = acquire_bus(&bus); r = acquire_bus(&bus);
if (r < 0) if (r < 0)
@ -743,78 +726,126 @@ static int inspect_homes(int argc, char *argv[], void *userdata) {
pager_open(arg_pager_flags); pager_open(arg_pager_flags);
char **args = strv_skip(argv, 1); STRV_FOREACH(i, items) {
if (args) { _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *myself = getusername_malloc(); _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
if (!myself) _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
_cleanup_(user_record_unrefp) UserRecord *hr = NULL;
const char *json;
int incomplete;
uid_t uid;
r = parse_uid(*i, &uid);
if (r < 0) {
if (!valid_user_group_name(*i, 0)) {
log_error("Invalid user name '%s'.", *i);
if (ret == 0)
ret = -EINVAL;
continue;
}
r = bus_call_method(bus, bus_mgr, "GetUserRecordByName", &error, &reply, "s", *i);
} else
r = bus_call_method(bus, bus_mgr, "GetUserRecordByUID", &error, &reply, "u", (uint32_t) uid);
if (r < 0) {
log_error_errno(r, "Failed to inspect home: %s", bus_error_message(&error, r));
if (ret == 0)
ret = r;
continue;
}
r = sd_bus_message_read(reply, "sbo", &json, &incomplete, NULL);
if (r < 0) {
bus_log_parse_error(r);
if (ret == 0)
ret = r;
continue;
}
r = sd_json_parse(json, SD_JSON_PARSE_SENSITIVE, &v, NULL, NULL);
if (r < 0) {
log_error_errno(r, "Failed to parse JSON identity: %m");
if (ret == 0)
ret = r;
continue;
}
hr = user_record_new();
if (!hr)
return log_oom(); return log_oom();
return inspect_home(bus, myself); r = user_record_load(hr, v, USER_RECORD_LOAD_REFUSE_SECRET|USER_RECORD_LOG|USER_RECORD_PERMISSIVE);
} else { if (r < 0) {
STRV_FOREACH(arg, args) if (ret == 0)
RET_GATHER(r, inspect_home(bus, *arg)); ret = r;
return r; continue;
}
hr->incomplete = incomplete;
dump_home_record(hr);
} }
return ret;
} }
static int authenticate_home(sd_bus *bus, const char *name) { static int authenticate_home(int argc, char *argv[], void *userdata) {
_cleanup_(user_record_unrefp) UserRecord *secret = NULL; _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r; _cleanup_strv_free_ char **items = NULL;
int r, ret = 0;
r = acquire_passed_secrets(name, &secret); r = mangle_user_list(strv_skip(argv, 1), &items);
if (r < 0) if (r < 0)
return r; return r;
for (;;) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
r = bus_message_new_method_call(bus, &m, bus_mgr, "AuthenticateHome");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", name);
if (r < 0)
return bus_log_create_error(r);
r = bus_message_append_secret(m, secret);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
if (r < 0) {
r = handle_generic_user_record_error(name, secret, &error, r, false);
if (r >= 0)
continue;
}
return r;
}
}
static int authenticate_homes(int argc, char *argv[], void *userdata) {
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
int r;
r = acquire_bus(&bus); r = acquire_bus(&bus);
if (r < 0) if (r < 0)
return r; return r;
(void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password); (void) polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
char **args = strv_skip(argv, 1); STRV_FOREACH(i, items) {
if (args) { _cleanup_(user_record_unrefp) UserRecord *secret = NULL;
_cleanup_free_ char *myself = getusername_malloc();
if (!myself)
return log_oom();
return authenticate_home(bus, myself); r = acquire_passed_secrets(*i, &secret);
} else { if (r < 0)
STRV_FOREACH(arg, args) return r;
RET_GATHER(r, authenticate_home(bus, *arg));
return r; for (;;) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
r = bus_message_new_method_call(bus, &m, bus_mgr, "AuthenticateHome");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(m, "s", *i);
if (r < 0)
return bus_log_create_error(r);
r = bus_message_append_secret(m, secret);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, HOME_SLOW_BUS_CALL_TIMEOUT_USEC, &error, NULL);
if (r < 0) {
r = handle_generic_user_record_error(*i, secret, &error, r, false);
if (r < 0) {
if (ret == 0)
ret = r;
break;
}
} else
break;
}
} }
return ret;
} }
static int update_last_change(sd_json_variant **v, bool with_password, bool override) { static int update_last_change(sd_json_variant **v, bool with_password, bool override) {
@ -4690,8 +4721,8 @@ static int run(int argc, char *argv[]) {
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_homes }, { "list", VERB_ANY, 1, VERB_DEFAULT, list_homes },
{ "activate", 2, VERB_ANY, 0, activate_home }, { "activate", 2, VERB_ANY, 0, activate_home },
{ "deactivate", 2, VERB_ANY, 0, deactivate_home }, { "deactivate", 2, VERB_ANY, 0, deactivate_home },
{ "inspect", VERB_ANY, VERB_ANY, 0, inspect_homes }, { "inspect", VERB_ANY, VERB_ANY, 0, inspect_home },
{ "authenticate", VERB_ANY, VERB_ANY, 0, authenticate_homes }, { "authenticate", VERB_ANY, VERB_ANY, 0, authenticate_home },
{ "create", VERB_ANY, 2, 0, create_home }, { "create", VERB_ANY, 2, 0, create_home },
{ "remove", 2, VERB_ANY, 0, remove_home }, { "remove", 2, VERB_ANY, 0, remove_home },
{ "update", VERB_ANY, 2, 0, update_home }, { "update", VERB_ANY, 2, 0, update_home },

View File

@ -46,17 +46,13 @@ static bool argv_has_at(pid_t pid) {
return c == '@'; return c == '@';
} }
static bool is_in_survivor_cgroup(const PidRef *pid) { static bool is_survivor_cgroup(const PidRef *pid) {
_cleanup_free_ char *cgroup_path = NULL; _cleanup_free_ char *cgroup_path = NULL;
int r; int r;
assert(pidref_is_set(pid)); assert(pidref_is_set(pid));
r = cg_pidref_get_path(/* root= */ NULL, pid, &cgroup_path); r = cg_pidref_get_path(/* root= */ NULL, pid, &cgroup_path);
if (r == -EUNATCH) {
log_warning_errno(r, "Process " PID_FMT " appears to originate in foreign namespace, ignoring.", pid->pid);
return true;
}
if (r < 0) { if (r < 0) {
log_warning_errno(r, "Failed to get cgroup path of process " PID_FMT ", ignoring: %m", pid->pid); log_warning_errno(r, "Failed to get cgroup path of process " PID_FMT ", ignoring: %m", pid->pid);
return false; return false;
@ -90,7 +86,7 @@ static bool ignore_proc(const PidRef *pid, bool warn_rootfs) {
return true; /* also ignore processes where we can't determine this */ return true; /* also ignore processes where we can't determine this */
/* Ignore processes that are part of a cgroup marked with the user.survive_final_kill_signal xattr */ /* Ignore processes that are part of a cgroup marked with the user.survive_final_kill_signal xattr */
if (is_in_survivor_cgroup(pid)) if (is_survivor_cgroup(pid))
return true; return true;
r = pidref_get_uid(pid, &uid); r = pidref_get_uid(pid, &uid);

View File

@ -7,26 +7,24 @@ TEST(audit_loginuid_from_pid) {
_cleanup_(pidref_done) PidRef self = PIDREF_NULL, pid1 = PIDREF_NULL; _cleanup_(pidref_done) PidRef self = PIDREF_NULL, pid1 = PIDREF_NULL;
int r; int r;
ASSERT_OK(pidref_set_self(&self)); assert_se(pidref_set_self(&self) >= 0);
ASSERT_OK(pidref_set_pid(&pid1, 1)); assert_se(pidref_set_pid(&pid1, 1) >= 0);
uid_t uid; uid_t uid;
r = audit_loginuid_from_pid(&self, &uid); r = audit_loginuid_from_pid(&self, &uid);
if (r != -ENODATA) assert_se(r >= 0 || r == -ENODATA);
ASSERT_OK(r);
if (r >= 0) if (r >= 0)
log_info("self audit login uid: " UID_FMT, uid); log_info("self audit login uid: " UID_FMT, uid);
ASSERT_ERROR(audit_loginuid_from_pid(&pid1, &uid), ENODATA); assert_se(audit_loginuid_from_pid(&pid1, &uid) == -ENODATA);
uint32_t sessionid; uint32_t sessionid;
r = audit_session_from_pid(&self, &sessionid); r = audit_session_from_pid(&self, &sessionid);
if (r != -ENODATA) assert_se(r >= 0 || r == -ENODATA);
ASSERT_OK(r);
if (r >= 0) if (r >= 0)
log_info("self audit session id: %" PRIu32, sessionid); log_info("self audit session id: %" PRIu32, sessionid);
ASSERT_ERROR(audit_session_from_pid(&pid1, &sessionid), ENODATA); assert_se(audit_session_from_pid(&pid1, &sessionid) == -ENODATA);
} }
static int intro(void) { static int intro(void) {