tools: reject invalid inputs and align machine-readable output (#43040)
This commit is contained in:
+3
-3
@@ -599,8 +599,8 @@ static int verb_encrypt(int argc, char *argv[], uintptr_t _data, void *userdata)
|
||||
|
||||
timestamp = arg_timestamp != USEC_INFINITY ? arg_timestamp : now(CLOCK_REALTIME);
|
||||
|
||||
if (arg_not_after != USEC_INFINITY && arg_not_after < timestamp)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before it is valid.");
|
||||
if (arg_not_after != USEC_INFINITY && arg_not_after <= timestamp)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before or when it becomes valid.");
|
||||
|
||||
if (geteuid() != 0 && !sd_id128_equal(arg_with_key, CRED_AES256_GCM_BY_NULL)) {
|
||||
(void) polkit_agent_open_if_enabled(BUS_TRANSPORT_LOCAL, arg_ask_password);
|
||||
@@ -1257,7 +1257,7 @@ static int vl_method_encrypt(sd_varlink *link, sd_json_variant *parameters, sd_v
|
||||
timestamp_fresh = true;
|
||||
} else
|
||||
timestamp_fresh = timestamp_is_fresh(p.timestamp);
|
||||
if (p.not_after != UINT64_MAX && p.not_after < p.timestamp)
|
||||
if (p.not_after != UINT64_MAX && p.not_after <= p.timestamp)
|
||||
return sd_varlink_error_invalid_parameter_name(link, "notAfter");
|
||||
|
||||
r = settle_scope(link, &p.scope, &p.uid, &cflags, /* any_scope_after_polkit= */ NULL);
|
||||
|
||||
@@ -890,7 +890,6 @@ static int action_dissect(
|
||||
_cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
|
||||
_cleanup_(table_unrefp) Table *t = NULL;
|
||||
_cleanup_free_ char *bn = NULL;
|
||||
uint64_t size = UINT64_MAX;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@@ -1009,7 +1008,7 @@ static int action_dissect(
|
||||
r = sd_json_buildo(
|
||||
&v,
|
||||
SD_JSON_BUILD_PAIR_STRING("name", bn),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(size != UINT64_MAX, "size", SD_JSON_BUILD_INTEGER(size)),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(m->image_size != UINT64_MAX, "size", SD_JSON_BUILD_INTEGER(m->image_size)),
|
||||
SD_JSON_BUILD_PAIR_INTEGER("sectorSize", m->sector_size),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(a >= 0, "architecture", SD_JSON_BUILD_STRING(architecture_to_string(a))),
|
||||
SD_JSON_BUILD_PAIR_CONDITION(!sd_id128_is_null(m->image_uuid), "imageUuid", SD_JSON_BUILD_UUID(m->image_uuid)),
|
||||
|
||||
@@ -998,6 +998,10 @@ static int prompt_root_shell(int rfd, sd_varlink **mute_console_link) {
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Failed to read credential passwd.shell.root, ignoring: %m");
|
||||
else {
|
||||
r = find_shell(rfd, arg_root_shell);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
log_debug("Acquired root shell from credential.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ static int verb_new(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
sd_id128_t id;
|
||||
int r;
|
||||
|
||||
if (!sd_id128_is_null(arg_app))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Verb \"new\" cannot be combined with --app-specific=.");
|
||||
|
||||
r = sd_id128_randomize(&id);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to generate ID: %m");
|
||||
|
||||
@@ -9493,6 +9493,11 @@ static int context_fstab(Context *context) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_dry_run) {
|
||||
log_notice("Running in dry run mode, not generating %s", arg_generate_fstab);
|
||||
return 0;
|
||||
}
|
||||
|
||||
path = path_join(arg_copy_source, arg_generate_fstab);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
@@ -9625,6 +9630,11 @@ static int context_crypttab(Context *context, bool late) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (arg_dry_run) {
|
||||
log_notice("Running in dry run mode, not generating %s", arg_generate_crypttab);
|
||||
return 0;
|
||||
}
|
||||
|
||||
path = path_join(arg_copy_source, arg_generate_crypttab);
|
||||
if (!path)
|
||||
return log_oom();
|
||||
|
||||
@@ -900,8 +900,8 @@ int encrypt_credential_and_warn(
|
||||
if (name && !credential_name_valid(name))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Invalid credential name: %s", name);
|
||||
|
||||
if (not_after != USEC_INFINITY && timestamp != USEC_INFINITY && not_after < timestamp)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before it is valid (" USEC_FMT " < " USEC_FMT ").", not_after, timestamp);
|
||||
if (not_after != USEC_INFINITY && timestamp != USEC_INFINITY && not_after <= timestamp)
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Credential is invalidated before or when it becomes valid (" USEC_FMT " <= " USEC_FMT ").", not_after, timestamp);
|
||||
|
||||
if (DEBUG_LOGGING) {
|
||||
char buf[FORMAT_TIMESTAMP_MAX];
|
||||
|
||||
@@ -2531,6 +2531,9 @@ static int verb_check_new(int argc, char *argv[], uintptr_t _data, void *userdat
|
||||
r = sd_json_variant_dump(json, arg_json_format_flags, stdout, NULL);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to print JSON: %m");
|
||||
|
||||
if (!context.candidate)
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
@@ -323,13 +323,24 @@ static int job_on_exit(sd_event_source *s, const siginfo_t *si, void *userdata)
|
||||
sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED,
|
||||
"Job terminated abnormally with signal %s.",
|
||||
signal_to_string(si->si_status));
|
||||
} else if (si->si_status != EXIT_SUCCESS)
|
||||
if (j->status_errno != 0)
|
||||
sd_bus_error_set_errno(&error, j->status_errno);
|
||||
else
|
||||
sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED,
|
||||
"Job failed with exit code %i.", si->si_status);
|
||||
else {
|
||||
} else if (si->si_status != EXIT_SUCCESS) {
|
||||
bool check_new_no_update = false;
|
||||
|
||||
if (j->type == JOB_CHECK_NEW &&
|
||||
si->si_status == EXIT_FAILURE &&
|
||||
job_parse_child_output(TAKE_FD(j->stdout_fd), &json) >= 0) {
|
||||
sd_json_variant *v = sd_json_variant_by_key(json, "available");
|
||||
check_new_no_update = v && sd_json_variant_is_null(v);
|
||||
}
|
||||
|
||||
if (!check_new_no_update) {
|
||||
if (j->status_errno != 0)
|
||||
sd_bus_error_set_errno(&error, j->status_errno);
|
||||
else
|
||||
sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED,
|
||||
"Job failed with exit code %i.", si->si_status);
|
||||
}
|
||||
} else {
|
||||
r = job_parse_child_output(TAKE_FD(j->stdout_fd), &json);
|
||||
if (r < 0)
|
||||
sd_bus_error_set_errnof(&error, r, "Failed to parse job worker output: %m");
|
||||
|
||||
+39
-9
@@ -468,6 +468,35 @@ static const char* pick_shell(const Item *i) {
|
||||
return NOLOGIN;
|
||||
}
|
||||
|
||||
static int read_shell_credential(const Item *i, char **ret) {
|
||||
_cleanup_free_ char *cn = NULL, *shell = NULL;
|
||||
int r;
|
||||
|
||||
assert(i);
|
||||
|
||||
cn = strjoin("passwd.shell.", i->name);
|
||||
if (!cn)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_credential(cn, (void**) &shell, /* ret_size= */ NULL);
|
||||
if (r < 0) {
|
||||
log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
|
||||
if (ret)
|
||||
*ret = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
path_simplify(shell);
|
||||
if (!valid_shell(shell))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Shell credential '%s' specifies invalid login shell '%s'.",
|
||||
cn, shell);
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(shell);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_temporary_passwd(
|
||||
Context *c,
|
||||
const char *passwd_path,
|
||||
@@ -488,6 +517,12 @@ static int write_temporary_passwd(
|
||||
goto done;
|
||||
|
||||
if (arg_dry_run) {
|
||||
ORDERED_HASHMAP_FOREACH(i, c->todo_uids) {
|
||||
r = read_shell_credential(i, /* ret= */ NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
log_info("Would write /etc/passwd%s", glyph(GLYPH_ELLIPSIS));
|
||||
goto done;
|
||||
}
|
||||
@@ -540,7 +575,7 @@ static int write_temporary_passwd(
|
||||
}
|
||||
|
||||
ORDERED_HASHMAP_FOREACH(i, c->todo_uids) {
|
||||
_cleanup_free_ char *creds_shell = NULL, *cn = NULL;
|
||||
_cleanup_free_ char *creds_shell = NULL;
|
||||
|
||||
struct passwd n = {
|
||||
.pw_name = i->name,
|
||||
@@ -559,15 +594,10 @@ static int write_temporary_passwd(
|
||||
.pw_shell = (char*) pick_shell(i),
|
||||
};
|
||||
|
||||
/* Try to pick up the shell for this account via the credentials logic */
|
||||
cn = strjoin("passwd.shell.", i->name);
|
||||
if (!cn)
|
||||
return -ENOMEM;
|
||||
|
||||
r = read_credential(cn, (void**) &creds_shell, NULL);
|
||||
r = read_shell_credential(i, &creds_shell);
|
||||
if (r < 0)
|
||||
log_debug_errno(r, "Couldn't read credential '%s', ignoring: %m", cn);
|
||||
else
|
||||
return r;
|
||||
if (creds_shell)
|
||||
n.pw_shell = creds_shell;
|
||||
|
||||
r = putpwent_sane(&n, passwd);
|
||||
|
||||
@@ -19,6 +19,7 @@ fi
|
||||
|
||||
systemd-dissect --json=short "$MINIMAL_IMAGE.raw" | \
|
||||
grep -F '{"rw":"ro","designator":"root","partition_uuid":null,"partition_label":null,"fstype":"squashfs","architecture":null,"verity":"external"' >/dev/null
|
||||
systemd-dissect --json=short "$MINIMAL_IMAGE.raw" | grep -F '"size":' >/dev/null
|
||||
systemd-dissect "$MINIMAL_IMAGE.raw" | grep -F "MARKER=1" >/dev/null
|
||||
# shellcheck disable=SC2153
|
||||
systemd-dissect "$MINIMAL_IMAGE.raw" | grep -F -f <(sed 's/"//g' "$OS_RELEASE") >/dev/null
|
||||
|
||||
@@ -167,6 +167,8 @@ systemd-creds --not-after="+1d" encrypt /tmp/cred.orig /tmp/cred.enc
|
||||
systemd-creds decrypt /tmp/cred.enc /tmp/cred.dec
|
||||
diff /tmp/cred.orig /tmp/cred.dec
|
||||
rm -f /tmp/cred.{enc,dec}
|
||||
ts="$(date -u '+%Y-%m-%d %H:%M:%S UTC')"
|
||||
(! systemd-creds --with-key=null --timestamp="$ts" --not-after="$ts" encrypt /tmp/cred.orig /tmp/cred.enc)
|
||||
|
||||
# Null-key credentials and the systemd.credentials_boot_policy= setting.
|
||||
#
|
||||
|
||||
@@ -2873,6 +2873,35 @@ EOF
|
||||
losetup -d "$loop"
|
||||
}
|
||||
|
||||
testcase_generate_fstab_dry_run() {
|
||||
local defs root
|
||||
|
||||
defs="$(mktemp --directory "/tmp/test-repart.defs.XXXXXXXXXX")"
|
||||
root="$(mktemp --directory "/var/test-repart.root.XXXXXXXXXX")"
|
||||
# shellcheck disable=SC2064
|
||||
trap "rm -rf '$defs' '$root'" RETURN
|
||||
chmod 0755 "$defs"
|
||||
|
||||
echo "*** testcase for skipping generated fstab in dry-run mode ***"
|
||||
|
||||
mkdir -p "$root/etc"
|
||||
tee "$defs/root.conf" <<EOF
|
||||
[Partition]
|
||||
Type=root
|
||||
Format=ext4
|
||||
MountPoint=/
|
||||
EOF
|
||||
|
||||
systemd-repart --pretty=yes \
|
||||
--definitions "$defs" \
|
||||
--dry-run=yes \
|
||||
--seed="$seed" \
|
||||
--generate-fstab="$root/etc/fstab" \
|
||||
-
|
||||
|
||||
test ! -e "$root/etc/fstab"
|
||||
}
|
||||
|
||||
testcase_encrypted_volume_empty_name() {
|
||||
local defs imgs
|
||||
|
||||
|
||||
@@ -143,9 +143,14 @@ new_version() {
|
||||
|
||||
check_no_new_update_available() {
|
||||
local client="${1:?}"
|
||||
local output
|
||||
|
||||
if [[ "$client" == "sysupdate-cli" ]]; then
|
||||
(! "$SYSUPDATE" --verify=no check-new)
|
||||
if output="$("$SYSUPDATE" --verify=no --json=short check-new)"; then
|
||||
exit 1
|
||||
fi
|
||||
[[ "$output" == '{"available":null}' ]]
|
||||
elif [[ "$client" == "varlink" ]]; then
|
||||
(! varlinkctl call "$VARLINK_SOCKET" io.systemd.SysUpdate.CheckNew '{"target":{"class":"host"}}') |& grep io.systemd.SysUpdate.NoUpdateNeeded >/dev/null
|
||||
else
|
||||
|
||||
@@ -352,6 +352,11 @@ grep -q "^root::" "$ROOT/etc/shadow"
|
||||
rm -fv "$ROOT/etc/passwd" "$ROOT/etc/shadow"
|
||||
|
||||
(! systemd-firstboot --root="$ROOT" --root-shell=/bin/nonexistentshell)
|
||||
WCREDS="$(mktemp -d)"
|
||||
printf '/bin/nonexistentshell' >"$WCREDS/passwd.shell.root"
|
||||
(! CREDENTIALS_DIRECTORY="$WCREDS" systemd-firstboot --root="$ROOT")
|
||||
[[ ! -e "$ROOT/etc/passwd" ]]
|
||||
rm -rf "$WCREDS"
|
||||
(! systemd-firstboot --root="$ROOT" --machine-id=invalidmachineid)
|
||||
(! systemd-firstboot --root="$ROOT" --timezone=Foo/Bar)
|
||||
|
||||
|
||||
@@ -36,7 +36,6 @@ systemd-id128 show root --value --json=short | jq -e '.id | type == "string"'
|
||||
systemd-id128 --json=short new | jq -e '.id | type == "string"'
|
||||
systemd-id128 new -p
|
||||
systemd-id128 new -u
|
||||
systemd-id128 new -a 4f68bce3e8cd4db196e7fbcaf984b709
|
||||
|
||||
systemd-id128 machine-id
|
||||
assert_eq "$(systemd-id128 --json=short machine-id | jq --raw-output .id)" "$(</etc/machine-id)"
|
||||
@@ -56,6 +55,7 @@ assert_eq "$(systemd-id128 boot-id --uuid)" "$(</proc/sys/kernel/random/boot_id)
|
||||
systemd-run --wait --pipe bash -euxc '[[ $INVOCATION_ID == "$(systemd-id128 invocation-id)" ]]'
|
||||
|
||||
(! systemd-id128)
|
||||
(! systemd-id128 new -a 4f68bce3e8cd4db196e7fbcaf984b709)
|
||||
(! systemd-id128 new -a '')
|
||||
(! systemd-id128 new -a '0')
|
||||
(! systemd-id128 invocation-id -a 4f68bce3e8cd4db196e7fbcaf984b709)
|
||||
|
||||
@@ -30,6 +30,15 @@ at_exit() {
|
||||
|
||||
trap at_exit EXIT
|
||||
|
||||
root="$(mktemp -d)"
|
||||
cred="$(mktemp -d)"
|
||||
mkdir -p "$root/etc"
|
||||
printf 'relative-shell' >"$cred/passwd.shell.creduser"
|
||||
(! env CREDENTIALS_DIRECTORY="$cred" systemd-sysusers --dry-run --root="$root" --inline 'u creduser 999 "Cred User" / -')
|
||||
(! env CREDENTIALS_DIRECTORY="$cred" systemd-sysusers --root="$root" --inline 'u creduser 999 "Cred User" / -')
|
||||
(! grep -F creduser "$root/etc/passwd" >/dev/null 2>&1)
|
||||
rm -rf "$root" "$cred"
|
||||
|
||||
# Ensure that a non-responsive NSS socket doesn't make sysusers fail
|
||||
mount -t tmpfs tmpfs /run/systemd/userdb/
|
||||
touch /run/systemd/userdb/io.systemd.DynamicUser
|
||||
|
||||
Reference in New Issue
Block a user